diff --git a/.distignore b/.distignore new file mode 100644 index 0000000..c964c7a --- /dev/null +++ b/.distignore @@ -0,0 +1,30 @@ +# Files and directories that must not ship in the WordPress.org package. +# build/ and vendor/ are deliberately absent: they are generated during the +# release workflow and are required at runtime. + +.git +.github +.gitignore +.distignore +.wordpress-org +.idea +.vscode +.DS_Store + +node_modules +tests +bin +assets/admin +assets/blocks + +composer.json +composer.lock +package.json +package-lock.json +webpack.config.js +phpcs.xml +phpcs.xml.dist +phpunit.xml +phpunit.xml.dist + +README.md diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..93207c9 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,61 @@ +name: CI + +on: + push: + branches: [ master, main ] + pull_request: + +jobs: + test: + name: Lint, test and build + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + php: [ '8.1', '8.2', '8.3' ] + + steps: + - uses: actions/checkout@v4 + + - name: Set up PHP ${{ matrix.php }} + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + coverage: none + + - name: Install PHP dependencies + run: composer install --no-interaction --prefer-dist + + - name: Lint PHP + run: | + find src inc tests -name '*.php' -print0 | xargs -0 -n1 -P4 php -l > /dev/null + php -l wp-performance.php + php -l advanced-cache.php + php -l object-cache.php + + - name: Test + run: php tests/run.php + + build: + name: Build assets + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Set up Node + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: npm + + - run: npm ci + - run: npm run build + + - name: Confirm the build produced what the plugin loads + run: | + test -f build/admin/app/index.js + test -f build/admin/app/index.asset.php + test -f build/admin/app.css + test -f build/blocks/cache/index.js diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 0000000..5abdabf --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,72 @@ +name: Deploy to WordPress.org + +# Pushing a version tag publishes that version. The tag is the single source of +# truth, so a release is exactly what was tagged. +on: + push: + tags: + - '[0-9]+.[0-9]+.[0-9]+' + - '[0-9]+.[0-9]+.[0-9]+.[0-9]+' + workflow_dispatch: + +jobs: + deploy: + name: Build and deploy + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Set up PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '8.1' + coverage: none + + - name: Set up Node + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: npm + + - name: Check the tag matches the plugin version + run: | + TAG="${GITHUB_REF_NAME}" + HEADER=$(grep -m1 '^ \* Version:' wp-performance.php | sed 's/.*Version:[[:space:]]*//' | tr -d '[:space:]') + STABLE=$(grep -m1 '^Stable tag:' readme.txt | sed 's/.*Stable tag:[[:space:]]*//' | tr -d '[:space:]') + echo "tag=$TAG header=$HEADER stable=$STABLE" + if [ "$TAG" != "$HEADER" ]; then + echo "::error::Tag $TAG does not match the Version header ($HEADER)." + exit 1 + fi + if [ "$STABLE" != "trunk" ] && [ "$TAG" != "$STABLE" ]; then + echo "::error::Tag $TAG does not match readme.txt Stable tag ($STABLE)." + exit 1 + fi + + - name: Install PHP dependencies + run: composer install --no-dev --optimize-autoloader --prefer-dist --no-interaction + + - name: Run tests + run: php tests/run.php + + - name: Build assets + run: | + npm ci + npm run build + + - name: Confirm the build produced what the plugin loads + run: | + test -f build/admin/app/index.js || { echo "::error::admin bundle missing"; exit 1; } + test -f build/admin/app/index.asset.php || { echo "::error::admin asset manifest missing"; exit 1; } + test -f build/admin/app.css || { echo "::error::admin stylesheet missing"; exit 1; } + test -f build/blocks/cache/index.js || { echo "::error::cache block bundle missing"; exit 1; } + test -f vendor/autoload.php || { echo "::error::autoloader missing"; exit 1; } + + - name: Deploy to the plugin directory + uses: 10up/action-wordpress-plugin-deploy@stable + env: + SVN_USERNAME: ${{ secrets.SVN_USERNAME }} + SVN_PASSWORD: ${{ secrets.SVN_PASSWORD }} + SLUG: wp-performance + ASSETS_DIR: .wordpress-org diff --git a/.gitignore b/.gitignore index ad2f8ef..59b6f22 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,8 @@ -includes/data/settings/*.json +/vendor/ +/vendor-prefixed/ +/node_modules/ +/build/ *.backup log.txt -wpp.js -vendor/ \ No newline at end of file +.DS_Store +.idea/ diff --git a/.wordpress-org/banner-1544x500.png b/.wordpress-org/banner-1544x500.png new file mode 100644 index 0000000..6bd9fda Binary files /dev/null and b/.wordpress-org/banner-1544x500.png differ diff --git a/.wordpress-org/banner-772x250.png b/.wordpress-org/banner-772x250.png new file mode 100644 index 0000000..1572ae8 Binary files /dev/null and b/.wordpress-org/banner-772x250.png differ diff --git a/.wordpress-org/icon-128x128.png b/.wordpress-org/icon-128x128.png new file mode 100644 index 0000000..f377339 Binary files /dev/null and b/.wordpress-org/icon-128x128.png differ diff --git a/.wordpress-org/icon-256x256.png b/.wordpress-org/icon-256x256.png new file mode 100644 index 0000000..93dff74 Binary files /dev/null and b/.wordpress-org/icon-256x256.png differ diff --git a/.wordpress-org/icon.svg b/.wordpress-org/icon.svg new file mode 100644 index 0000000..66c66a6 --- /dev/null +++ b/.wordpress-org/icon.svg @@ -0,0 +1,53 @@ + + WP Performance + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.wordpress-org/screenshot-1.png b/.wordpress-org/screenshot-1.png new file mode 100644 index 0000000..5ba5d82 Binary files /dev/null and b/.wordpress-org/screenshot-1.png differ diff --git a/.wordpress-org/screenshot-2.png b/.wordpress-org/screenshot-2.png new file mode 100644 index 0000000..8e604ef Binary files /dev/null and b/.wordpress-org/screenshot-2.png differ diff --git a/.wordpress-org/screenshot-3.png b/.wordpress-org/screenshot-3.png new file mode 100644 index 0000000..cc4f7ab Binary files /dev/null and b/.wordpress-org/screenshot-3.png differ diff --git a/.wordpress-org/screenshot-4.png b/.wordpress-org/screenshot-4.png new file mode 100644 index 0000000..7b56e4c Binary files /dev/null and b/.wordpress-org/screenshot-4.png differ diff --git a/.wordpress-org/screenshot-5.png b/.wordpress-org/screenshot-5.png new file mode 100644 index 0000000..5b56cad Binary files /dev/null and b/.wordpress-org/screenshot-5.png differ diff --git a/README.md b/README.md index 0136615..7f9f878 100644 --- a/README.md +++ b/README.md @@ -1,250 +1,62 @@ -# WP Performance # +# WP Performance -[![](https://img.shields.io/wordpress/plugin/tested/wp-performance.svg)](https://wordpress.org/plugins/wp-performance) [![](https://img.shields.io/wordpress/plugin/stars/wp-performance.svg)](https://wordpress.org/plugins/wp-performance) [![](https://img.shields.io/wordpress/plugin/dt/wp-performance.svg)](https://wordpress.org/plugins/wp-performance) [![](https://img.shields.io/wordpress/plugin/v/wp-performance.svg)](https://wordpress.org/plugins/wp-performance) +[![Tested](https://img.shields.io/wordpress/plugin/tested/wp-performance.svg)](https://wordpress.org/plugins/wp-performance) [![Rating](https://img.shields.io/wordpress/plugin/stars/wp-performance.svg)](https://wordpress.org/plugins/wp-performance) [![Downloads](https://img.shields.io/wordpress/plugin/dt/wp-performance.svg)](https://wordpress.org/plugins/wp-performance) [![Version](https://img.shields.io/wordpress/plugin/v/wp-performance.svg)](https://wordpress.org/plugins/wp-performance) -## Description ## +Cache and performance plugin for WordPress. Page caching, CSS/JS/HTML optimization, modern image formats and Core Web Vitals tooling, with a React admin. -WP Performance is a cache & performance plugin which makes optimizing your site really easy. -This plugin generates static html files from your dynamic content and it uses mod_rewrite to load the cache files which is the fastest method. +Version 2.0 is a ground-up rewrite: no third-party PHP dependencies, its own cache engine, asset parser and minifiers. -## Features ## +## Features -* Page cache -* Cache preloading -* Browser cache -* GZIP Compression -* Minify CSS, JavaScript, and HTML -* Asynchronously load CSS/JavaScript -* Combine CSS/JavaScript -* Disable CSS/JavaScript -* Resource hints -* Critical CSS path generator -* Database Cleaner -* Export/import settings -* Lazy Load images ( supports native lazy load ) -* Lazy Load videos ( supports native lazy load ) -* Responsive images -* Regenerate thumbs -* CDN -* WP-CLI Support +**Caching** page cache served before WordPress loads, block cache for parts of a page, cache preloading, browser caching, GZIP, optional Redis object cache. -## Add-ons ## +**CSS** minify, combine, load without blocking, remove unused CSS per page, critical CSS, self-host Google Fonts, resource hints. -* Cloudflare integration -* Varnish cache -* Dynamic page preload +**JavaScript** minify, combine, defer, delay until interaction, disable per file or per page. +**Media** lazy load, responsive images, missing width/height for CLS, LCP preload with fetchpriority, WebP and AVIF conversion. -## Supported languages ## +**Also** HTML minification, database cleanup, CDN rewriting, one-click presets, health checks, restore points, WP-CLI, multisite. -* English -* Hrvatski -* 中文 (by @cmhello) +Add-ons for Cloudflare, Varnish and link prefetching ship with the plugin. -## Installation ## +## Requirements -1. Upload "wp-performance" to the "/wp-content/plugins/" directory -2. Activate the plugin through the Plugins menu in WordPress +- WordPress 6.9 or newer +- PHP 8.1 or newer +## Development -## WP-CLI Support ## +```bash +composer install # autoloader +npm install # build toolchain +npm run build # compile the admin app and blocks into build/ +npm start # watch mode +``` -* **wp wpp flush** - Clear the cache -* **wp wpp disable** - Temporarily disable WP Performance -* **wp wpp enable** - Enable WP Performance -* **wp wpp cleanup** - Run all database cleanups -* **wp wpp cleanup trash** - Run trash cleanup -* **wp wpp cleanup spam** - Run spam cleanup -* **wp wpp cleanup revisions** - Run revisions cleanup -* **wp wpp cleanup drafts** - Run drafts cleanup -* **wp wpp cleanup transients** - Run transients cleanup -* **wp wpp cleanup cron** - Run cron tasks cleanup +`build/` and `vendor/` are generated and not committed, so both commands are required before the plugin will run from a clone. +### Tests -## Changelog ## +```bash +composer test # every suite +php tests/run.php cache # suites matching "cache" +``` +The suites are standalone: they stub the slice of the WordPress API the code touches, so they need no database and no WordPress install. See [tests/README.md](tests/README.md). -### 1.1.8.3 ### -* [FIX] Cloudflare add-on - respect existing headers +### Translations -### 1.1.8.2 ### -* [FIX] Prefetch add-on again +```bash +bin/make-translations.sh +``` -### 1.1.8.1 ### -* [FIX] Prefetch add-on +Regenerates `languages/wpp.pot`, compiles each `.po`, and builds the script-translation JSON the admin bundle loads. Requires WP-CLI and GNU gettext. +## Reporting bugs -### 1.1.8 ### -* [NEW] HTML optimization -* [NEW] Google Fonts display optimization -* [NEW] Exclude CSS/JS files from asynchronous loading -* [UPDATE] Translations -* [FIX] Asynchronous JS loading +Open an issue on [GitHub](https://github.com/alaca/WP-Performance/issues). +## License -### 1.1.7.4 ### -* [FIX] Combine CSS -* [FIX] Combine JS - -### 1.1.7.3 ### -* [FIX] Update UI - Checkboxes -* [FIX] Skip dynamic files - -### 1.1.7.2 ### -* [FIX] Combined resource path errors -* [FIX] Identifiy local resources without URL scheme - -### 1.1.7.1 ### -* [FIX] htaccess errors - -### 1.1.7 ### -* [NEW] Cloudflare Add-on - purge individual cache -* [NEW] Option to keep generated JS/CSS files when flushing the cache -* [FIX] Lazy Load issues in MSIE - -### 1.1.6.2 ### -* [FIX] HTML minify - -### 1.1.6.1 ### -* [FIX] Lazyload issues - -### 1.1.6 ### -* [NEW] Lazy load videos -* [NEW] Disable Emojis -* [NEW] Disable Embeds -* [UPDATE] Translations -* [IMPROVE] Admin UI -* [FIX] Load/Save settings -* [FIX] Minor bugfixes - -### 1.1.5.1 ### -* [FIX] Fix WooCommerce Add to cart error - -### 1.1.5 ### -* [IMPROVE] Minify JS -* [IMPROVE] Minify CSS -* [IMPROVE] Minify HTML -* [IMPROVE] Images LazyLoad -* [IMPROVE] Async JavaScript -* [IMPROVE] Prefetch Add-on -* [FIX] Cache dir path - -### 1.1.4.2 ### -* [IMPROVE] Minify JS -* [IMPROVE] Process CSS import rules - -### 1.1.4.1 ### -* [FIX] Minify HTML - -### 1.1.4 ### -* [NEW] Multisite support -* [NEW] AMP support - -### 1.1.3.4 ### -* [FIX] Clear log file after clearing the cache -* [FIX] Wrong optimization status message in WPP metabox on edit page screen -* [IMPROVE] Admin UI -* [IMPROVE] Cloudflare add-on -* [IMPROVE] Dynamic page preload add-on -* [UPDATE] languages - -### 1.1.3.3 ### -* [FIX] Disable resources on selected URL -* [UPDATE] Chinese language file - -### 1.1.3.2 ### -* [FIX] Parser minify error - -### 1.1.3.1 ### -* [FIX] Autoloader errors - -### 1.1.3 ### -* [NEW] Dynamic page preload addon -* [NEW] Minify HTML - -### 1.1.2 ### -* [UPDATE] Chinese language file - -### 1.1.1 ### -* [NEW] Remove cache directory after uninstall -* [IMPROVE] Move log file into cache dir -* [FIX] Empty template errors - -### 1.1.0 ### -* [NEW] Exclude user agents from cache -* [NEW] Exclude search engines from cache -* [NEW] Add-ons page -* [IMPROVE] Admin UI -* [FIX] XML files cache - -### 1.0.9 ### -* [IMPROVE] JavaScript async loading -* [IMPROVE] Security -* [IMPROVE] Parser -* [FIX] Exclude urls -* [FIX] LazyLoad - - -### 1.0.8.1 ### -* [FIX] Minor bug fixes - -### 1.0.8 ### -* [NEW] Cloudflare integration -* [IMPROVE] Admin UI for desktop devices -* [IMPROVE] Admin UI for mobile devices -* [FIX] Disabled resources disappearing options -* [FIX] Minor bugfixes - -### 1.0.7 ### -* [FIX] Add items to menu error -* [FIX] Parser warnings for responsive images -* [IMPROVE] Admin UI on mobile devices - -### 1.0.6 ### -* [NEW] Group resources ( Theme, Plugins, External ) -* [IMPROVE] Security -* [IMPROVE] Admin UI on mobile devices -* [UPDATE] Translations -* [FIX] Disable external resources -* [FIX] Clear cache on front-page -* [FIX] Various minor bugfixes - -### 1.0.5 ### -* [NEW] Drafts cleanup -* [NEW] WP CLI commands - database cleanups -* [IMPROVE] Admin UI -* [UPDATE] Translations -* [FIX] Minor bugfixes - -### 1.0.4 ### -* [NEW] Resource hints -* [NEW] Exclude page from Image optimization on edit page screen -* [NEW] Exclude URL(s) from Image optimization -* [IMPROVE] Metabox UI on Edit page -* [IMPROVE] Admin UI -* [UPDATE] Translations -* [FIX] Cron tasks cleanup -* [FIX] Combine Google fonts - -### 1.0.3 ### -* [NEW] Cron tasks cleanup -* [NEW] Exclude page from Cache, JS and CSS optimization on edit page screen -* [NEW] Admin toolbar links -* [IMPROVE] Admin Database UI -* [IMPROVE] Admin UI on mobile devices -* [UPDATE] Translations -* [FIX] htaccess backup handling -* [FIX] Minor bugfixes - -### 1.0.2 ### -* [NEW] Detect server software -* [NEW] Generate NGINX rewrite rules -* [NEW] Clear collected files list -* [IMPROVE] Admin UI -* [UPDATE] Translations -* [FIX] Htaccess permissions notice - -### 1.0.1 ### -* [FIX] PCRE2 parser issues -* [FIX] Clear cache JS error -* [NEW] Chinese translation \ No newline at end of file +GPL-2.0-or-later. diff --git a/advanced-cache.php b/advanced-cache.php new file mode 100644 index 0000000..367b9b0 --- /dev/null +++ b/advanced-cache.php @@ -0,0 +1,315 @@ + 0; $i--) { + $base = $cacheDir . $host . wpp_dropin_path_key(array_slice($segments, 0, $i)); + foreach ([$base . '.json.php', $base . '.json'] as $file) { + if (is_file($file)) { + return $file; + } + } + } + + foreach ([$cacheDir . $host . '.json.php', $cacheDir . $host . '.json'] as $file) { + if (is_file($file)) { + return $file; + } + } + + return ''; + } +} + +if (! function_exists('wpp_dropin_stripped_query')) { + function wpp_dropin_stripped_query(string $query): string + { + if ($query === '') { + return ''; + } + $tracking = [ + 'utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', + 'gclid', 'fbclid', 'gad_source', 'gbraid', 'wbraid', 'msclkid', + 'mc_cid', 'mc_eid', '_ga', '_gl', 'usqp', 'age-verified', + ]; + parse_str($query, $params); + foreach ($tracking as $param) { + unset($params[$param]); + } + if ($params === []) { + return ''; + } + ksort($params); + return http_build_query($params); + } +} + +if (! function_exists('wpp_dropin_is_mobile')) { + // Mirrors wp_is_mobile(), which is what PageCache uses to pick the variant + // it writes. Any divergence hands phone HTML to desktops and back. + function wpp_dropin_is_mobile(string $ua, ?string $hint): bool + { + if ($hint !== null) { + return $hint === '?1'; + } + if ($ua === '') { + return false; + } + foreach (['Mobile', 'Android', 'Silk/', 'Kindle', 'BlackBerry', 'Opera Mini', 'Opera Mobi'] as $token) { + if (strpos($ua, $token) !== false) { + return true; + } + } + + return false; + } +} + +if (! function_exists('wpp_dropin_canonical')) { + function wpp_dropin_canonical(string $requestUri, bool $trailingSlash): bool + { + $path = explode('?', $requestUri, 2)[0]; + $norm = '/' . trim(str_replace('..', '', $path), '/'); + if ($norm !== '/' && $trailingSlash) { + $norm .= '/'; + } + + return $path === $norm && strpos($path, '//') === false; + } +} + +if (! function_exists('wpp_dropin_accepts_gzip')) { + function wpp_dropin_accepts_gzip(string $header): bool + { + $accepted = false; + foreach (explode(',', strtolower($header)) as $part) { + $bits = explode(';', $part); + $token = trim($bits[0]); + if ($token !== 'gzip' && $token !== '*') { + continue; + } + $q = 1.0; + foreach (array_slice($bits, 1) as $param) { + $param = str_replace(' ', '', $param); + if (strpos($param, 'q=') === 0) { + $q = (float) substr($param, 2); + } + } + if ($token === 'gzip') { + return $q > 0; + } + $accepted = $q > 0; + } + + return $accepted; + } +} + +if (! function_exists('wpp_dropin_vary')) { + function wpp_dropin_vary(bool $mobile): string + { + return 'Accept-Encoding' . ($mobile ? ', User-Agent' : ''); + } +} + +if (! function_exists('wpp_dropin_file')) { + function wpp_dropin_file(string $cacheDir, string $host, string $requestUri, bool $permalinks, bool $mobile): string + { + $parts = explode('?', $requestUri, 2); + $path = '/' . trim(str_replace('..', '', $parts[0]), '/'); + if ($path !== '/') { + $path .= '/'; + } + $query = wpp_dropin_stripped_query($parts[1] ?? ''); + + if ($permalinks) { + $dir = $cacheDir . $host . $path; + $key = $query !== '' ? md5($query) : 'index'; + } else { + $dir = $cacheDir . $host . '/'; + $key = md5($host . $path . ($query !== '' ? '?' . $query : '')); + } + + return $dir . $key . ($mobile ? '-mobile' : '') . '.html'; + } +} + +// Only cache plain GET requests with no POST payload. +if (($_SERVER['REQUEST_METHOD'] ?? 'GET') !== 'GET') { + return; +} +if (! empty($_POST)) { + return; +} + +$wpp_host = wpp_dropin_host((string) ($_SERVER['HTTP_HOST'] ?? '')); +$wpp_dir = WP_CONTENT_DIR . '/cache/wpp-cache/'; +$wpp_uri = $_SERVER['REQUEST_URI'] ?? '/'; + +$wpp_conf = wpp_dropin_conf($wpp_dir, $wpp_host, $wpp_uri); +if ($wpp_conf === '') { + return; +} + +$wpp_raw = (string) file_get_contents($wpp_conf); +if (strncmp($wpp_raw, ' 0 && (time() - $wpp_mtime) > $wpp_expire) { + return; +} + +// The body varies on Accept-Encoding, and on User-Agent when the mobile variant +// is in play. Without this a shared proxy replays one variant to every client. +header('Vary: ' . wpp_dropin_vary(! empty($wpp_settings['mobile']))); + +if (! empty($_SERVER['HTTP_IF_MODIFIED_SINCE']) && strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) >= $wpp_mtime) { + header('HTTP/1.1 304 Not Modified'); + exit; +} + +header('Last-Modified: ' . gmdate('D, d M Y H:i:s', $wpp_mtime) . ' GMT'); +header('Content-Type: text/html; charset=UTF-8'); +header('X-WPP-Cache: HIT'); + +if (wpp_dropin_accepts_gzip((string) ($_SERVER['HTTP_ACCEPT_ENCODING'] ?? '')) + && is_file($wpp_file . '.gz') + && filemtime($wpp_file . '.gz') >= $wpp_mtime +) { + header('Content-Encoding: gzip'); + readfile($wpp_file . '.gz'); + exit; +} + +readfile($wpp_file); +exit; diff --git a/assets/admin.js b/assets/admin.js deleted file mode 100644 index da7debb..0000000 --- a/assets/admin.js +++ /dev/null @@ -1,1023 +0,0 @@ -/** - * WP Performance Admin - */ -jQuery(document).ready(function ($) { - - jconfirm.defaults = { - title: WPP.lang.confirm, - theme: 'supervan', - useBootstrap: false, - draggable: false, - }; - - - function _removeUnusedFields() { - $('.wpp-dynamic-input').each(function () { - if ($(this).attr('required') && !$(this).val()) { - $(this).parent('.wpp-dynamic-input-container').remove(); - } - }); - } - - $(document).on('click', '#wpp_tabs_menu li a', function (e) { - e.preventDefault(); - var tab = $(this).data('wpp-page-id'); - $('#wpp_tab').val(tab); - $('#wpp_tabs_menu a, .wpp_page').removeClass('active'); - $('[data-wpp-page="' + tab + '"]').add(this).addClass('active'); - // Remove empty required fields on change tab - _removeUnusedFields(); - }); - - $(document).on('click', '[data-wpp-show-page]', function (e) { - e.preventDefault(); - var tab = $(this).data('wpp-show-page'); - var highlight = $(this).data('wpp-highlight'); - - $('[data-wpp-page-id="' + tab + '"]').click(); - - if (highlight) { - var container = $('[data-wpp-highlight-id="' + highlight + '"]'); - container.addClass('wpp-highlight'); - setTimeout(function () { - container.one('hover', function () { - $(this).removeClass('wpp-highlight'); - }); - }, 500); - } - }); - - $(document).on('change', '#wpp_mobile_menu select', function (e) { - e.preventDefault(); - var tab = $(this).val(); - $('#wpp_tab').val(tab); - $('#wpp_tabs_menu a, .wpp_page').removeClass('active'); - $('[data-wpp-page="' + tab + '"]').add(this).addClass('active'); - // Remove empty required fields on change tab - _removeUnusedFields(); - }); - - /** - * Select rules - */ - $(document).on('click', '.wpp-select-rules', function (e) { - e.preventDefault(); - $('.wpp-rules-textarea').select(); - }); - - - /** - * Remove excluded page - */ - $('.wpp-remove-manually-excluded').on('click', function (e) { - e.preventDefault(); - - var that = this; - var id = $(this).data('id'); - var type = $(this).data('type'); - - $.confirm({ - content: $(this).data('description'), - buttons: { - Confirm: function () { - - $.ajax({ - method: 'POST', - url: ajaxurl, - data: { - id: id, - type: type, - action: 'wpp_remove_post_options', - nonce: WPP.nonce - } - }).done(function () { - $(that).parent('.wpp-dynamic-input-container').fadeOut(); - }); - - }, - Cancel: function () { } - } - }); - - }); - - - /** - * Checkbox confirmation - */ - $('.wpp-action-confirm').on('click', function (e) { - - var that = this; - - if ($(that).is(':checked')) { - - $.confirm({ - content: $(this).data('description'), - buttons: { - Confirm: function () { - - $(that).attr('checked', true); - - }, - Cancel: function () { - $(that).attr('checked', false); - } - } - }); - - } else { - $(that).attr('checked', false); - } - - }); - - - /** - * Toggle options - */ - $('[data-wpp-toggle-id]').on('click', function (e) { - - e.preventDefault(); - - var id = $(this).data('wpp-toggle-id'); - var show = $(this).data('wpp-toggle-show'); - var hide = $(this).data('wpp-toggle-hide'); - var toggle = $('[data-wpp-toggle="' + id + '"]'); - - if (toggle.hasClass('wpp-hidden')) { - toggle.removeClass('wpp-hidden'); - $(this).text(hide); - } else { - toggle.addClass('wpp-hidden'); - $(this).text(show); - } - - }); - - /** - * Show hide containers depending on checked options - */ - $('[data-wpp-checkbox]').each(function () { - - var name = $(this).data('wpp-checkbox'); - - if ($(this).is(':checked')) { - - if (name.indexOf('|') !== -1) { - - var names = name.split('|'); - - for (var i in names) { - $('[data-wpp-show-checked="' + names[i] + '"]').show(); - } - - } else { - $('[data-wpp-show-checked="' + name + '"]').show(); - } - - } - - }); - - - /** - * Show hide containers on click - */ - $(document).on('click', '[data-wpp-checkbox]', function (e) { - - var containers = []; - - var name = $(this).data('wpp-checkbox'); - - if (name.indexOf('|') !== -1) { - - var names = name.split('|'); - - for (var n in names) { - containers.push(names[n]); - } - - } else { - containers.push(name); - } - - for (var j in containers) { - - var variations = $('[data-wpp-checkbox*="' + containers[j] + '"]'); - - if (variations.length > 1) { - - var checked = false; - - $.each(variations, function (i, v) { - - if ($(v).is(':checked')) { - checked = true; - return; - } - - }); - - if (checked) { - $('[data-wpp-show-checked="' + containers[j] + '"]').show(); - } else { - $('[data-wpp-show-checked="' + containers[j] + '"]').hide(); - } - - } else { - $('[data-wpp-show-checked="' + containers[j] + '"]').toggle(); - } - - } - - }); - - /** - * Clear cache - */ - $(document).on('click', '#wpp-clear-cache, li.wpp_clear_cache a', function (e) { - - e.preventDefault(); - - $.confirm({ - content: $(this).data('description') || $(this).attr('title'), - buttons: { - Confirm: function () { - - $('body').append('
'); - - $.ajax({ - method: 'POST', - url: ajaxurl, - dataType: 'json', - data: { - action: 'wpp_clear_cache' - } - }).done(function () { - $('#wpp_overlay').remove(); - $('#wpp-cache-size span').html('0.00'); - }); - - }, - Cancel: function () { } - } - }); - - }); - - - /** - * Get critical css path - */ - $(document).on('click', '#wpp-get-critical-css', function (e) { - - e.preventDefault(); - - var btn = $(this); - - if (btn.attr('disabled') === 'disabled') return false; - - btn.attr('disabled', true); - - btn.after(''); - - $.ajax({ - method: 'POST', - url: ajaxurl, - dataType: 'json', - data: { - action: 'wpp_get_critical_css_path', - nonce: WPP.nonce - } - }).done(function (response) { - - if (response.status) { - $('#wpp-css-custom-path-def').val(response.data); - } else { - console.log(response.message); - btn.attr('disabled', false); - } - - $('#wpp-ajax-loader').remove(); - - }).fail(function () { - - btn.attr('disabled', false); - $('#wpp-ajax-loader').remove(); - - }); - - }); - - - /** - * Enable get critical css path btn - */ - $(document).on('keyup', '#wpp-css-custom-path-def', function (e) { - - if (!$(this).val()) { - $('#wpp-get-critical-css').removeAttr('disabled'); - } - - }); - - - - /** - * Update group of options - */ - $(document).on('click', '.wpp-update-checkboxes', function (e) { - - var that = this; - - var items = $('[data-wpp-group="' + $(this).data('wpp-group') + '"]').not(':disabled'); - - $.each(items, function (i, e) { - - var checked = $(that).is(':checked'); - var show = $(e).data('wpp-show-option'); - - $(e).prop('checked', checked); - - if (show && checked) { - - var index = $(e).data('wpp-index'); - var file = $(e).data('wpp-file'); - var name = $(e).data('wpp-name'); - var prefix = $(e).data('wpp-prefix'); - var data = $(e).data('wpp-option-data'); - - $(this).parents('tr').addClass('wpp-disabled-row'); - - // Check if option already exists - if (!$('[data-wpp-option="' + show + '"]').length) { - - // Add option - var select = '
'; - select += ''; - select += '
'; - - $(this).parent().siblings('.wpp-list-filename').append(select); - - } - - } else { - - $(this).parents('tr').removeClass('wpp-disabled-row'); - - $('[data-wpp-option="' + show + '"]').remove(); - - } - - var option = $(e).data('wpp-disable-option'); - - if (option) { - - var options = option.split('|'); - - for (var i in options) { - $('input[name="' + options[i] + '"]').not('[data-disabled]').attr('disabled', $(e).is(':checked')); - - if (show && checked) { - $('[data-wpp-option="' + show + '"]').removeClass('wpp-hidden'); - } else { - $('[data-wpp-option="' + show + '"]').addClass('wpp-hidden'); - } - - } - - } - - }); - }); - - - /** - * Disable option - */ - $('[data-wpp-disable-option]').on('click', function () { - - var option = $(this).data('wpp-disable-option'); - var checked = $(this).is(':checked'); - var show = $(this).data('wpp-show-option'); - - - if (show && checked) { - - var index = $(this).data('wpp-index'); - var file = $(this).data('wpp-file'); - var name = $(this).data('wpp-name'); - var prefix = $(this).data('wpp-prefix'); - var data = $(this).data('wpp-option-data'); - - - $(this).parents('tr').addClass('wpp-disabled-row'); - - // Remove if already exists - $('[data-wpp-option="' + show + '"]').remove(); - - // Add option - var select = '
'; - select += ''; - select += '
'; - - $(this).parent().siblings('.wpp-list-filename').append(select); - - } else { - - if (show) { - $(this).parents('tr').removeClass('wpp-disabled-row'); - } - - - $('[data-wpp-option="' + show + '"]').remove(); - - } - - if (option) { - - var options = option.split('|'); - - for (var i in options) { - - $('input[name="' + options[i] + '"]').not('[data-disabled]').attr('disabled', checked); - - if (show && checked) { - $('[data-wpp-option="' + show + '"]').removeClass('wpp-hidden'); - } else { - $('[data-wpp-option="' + show + '"]').addClass('wpp-hidden'); - } - } - - } - - }); - - /** - * Disable position options - */ - $(document).on('change', '.wpp-disable-select-position', function () { - - var position = $(this).val(); - var file = $(this).data('wpp-file'); - var prefix = $(this).data('wpp-prefix'); - var container = $(this).data('wpp-container'); - var data_options = $(this).data('wpp-options'); - - var options = (data_options) ? data_options.split('|') : false; - - switch (position) { - case 'selected': - case 'except': - - $('#' + container).html(''); - $('[data-container="#' + container + '"]').remove(); - - $('#' + container).after('' + WPP.lang.add_url + ''); - - $('[data-add-input="' + prefix + '_disable_' + position + '[' + file + '][]"]').click(); - - $.each(options, function (i, name) { - - $('input[name="' + name + '[' + file + ']"]').not('[data-disabled]').attr('disabled', false); - - }); - - break; - default: - - $('#' + container).html(''); - $('[data-container="#' + container + '"]').remove(); - - if (options) { - - $.each(options, function (i, name) { - - $('input[name="' + name + '[' + file + ']"]').attr('disabled', true); - - }); - - } - - } - - }); - - /** - * Add image size - */ - $(document).on('click', '#wpp-add-image-size', function (e) { - - e.preventDefault(); - - var row = ' '; - row += ' '; - row += ' '; - row += ' '; - row += 'Save x'; - - var lastSize = $('#wpp-image-sizes-table tbody tr:last-child'); - - if (lastSize.length > 0) { - lastSize.after(row); - } else { - $('#wpp-image-sizes-table tbody').html(row); - } - - }); - - - /** - * Remove image size - */ - $(document).on('click', '.wpp-remove-user-image-size', function (e) { - - e.preventDefault(); - - var self = $(this); - var name = self.data('size-name'); - var description = self.data('description'); - - if (name) { - - $.confirm({ - content: description, - buttons: { - Confirm: function () { - - self.parents('tr').remove(); - - $.ajax({ - method: 'POST', - url: ajaxurl, - dataType: 'json', - data: { - action: 'wpp_images_action', - image_action: 'remove_size', - size: name, - nonce: WPP.nonce - } - }).done(function (response) { - - if (!response.status) { - $('#wpp-image-errors').text(response.error); - } - - }); - - }, - Cancel: function () { } - } - }); - - } else { - - self.parents('tr').remove(); - - } - - }); - - - /** - * Restore original image sizes - */ - $(document).on('click', '#wpp-restore-image-sizes', function (e) { - - e.preventDefault(); - - var description = $(this).data('description'); - - $.confirm({ - content: description, - buttons: { - Confirm: function () { - - $.ajax({ - method: 'POST', - url: ajaxurl, - dataType: 'json', - data: { - action: 'wpp_images_action', - image_action: 'restore_sizes', - nonce: WPP.nonce - }, - - }).done(function (response) { - - if (response.status) { - - // response from first request? hmm... - $.post(ajaxurl, { action: 'wpp_images_action', image_action: 'get_all_sizes', nonce: WPP.nonce }, function (data) { - - var tableBody = $('#wpp-image-sizes-table tbody'); - - tableBody.html(''); - - data.sizes.forEach(function (size) { - - var row = '' + size.name + ''; - row += '' + size.width + ' px'; - row += (size.height > 0) ? '' + size.height + ' px' : ''; - row += '' + ((size.crop > 0) ? WPP.lang.yes : '') + ''; - row += 'x'; - - tableBody.append(row); - - }); - - }); - - } else { - - $('#wpp-image-errors').text(response.error); - - } - - }); - - }, - Cancel: function () { } - } - }); - - - }); - - - /** - * Save image size - */ - $(document).on('click', '.wpp-save-image-size', function (e) { - - e.preventDefault(); - - $('#wpp-image-errors').text(''); - - var that = $(this); - var errors = false; - var inputs = $(this).parents('tr').find('input'); - - $.each(inputs, function (i, input) { - - var element = $(input); - - if (element.attr('name') == 'crop') { - return true; - } - - element.one('keyup', function () { - element.removeClass('wpp-border-error'); - }); - - if (!element.val()) { - errors = true; - element.addClass('wpp-border-error'); - } - - if (element.attr('name') == 'name') { - - if (/[^a-zA-Z0-9-_]/.test(element.val())) { - errors = true; - element.addClass('wpp-border-error'); - } - - } else { - - if (isNaN(element.val())) { - errors = true; - element.addClass('wpp-border-error'); - } - - } - - - }); - - if (!errors) { - - $.ajax({ - method: 'POST', - url: ajaxurl, - dataType: 'json', - data: { - action: 'wpp_images_action', - image_action: 'add_size', - size: inputs.serialize(), - nonce: WPP.nonce - - } - }).done(function (response) { - - if (response.status) { - - $.each(inputs, function (i, input) { - - var element = $(input); - - if (element.attr('name') == 'crop') { - - if (element.is(':checked')) { - element.replaceWith(WPP.lang.yes); - } else { - element.replaceWith(''); - } - - return true; - } - - if (element.attr('name') != 'name') { - element.replaceWith(element.val() + ' px'); - } else { - element.replaceWith(element.val()); - } - - }); - - that.remove(); - - } else { - - $('#wpp-image-errors').text(response.error); - - setTimeout(function () { - $('#wpp-image-errors').text(''); - }, 3000); - - } - - }); - - } - - }); - - - /** - * Regenerate thumbnails - */ - $(document).on('click', '#wpp-regenerate-thumbnails', function (e) { - - e.preventDefault(); - - var that = $(this); - var title = that.data('title'); - var removeFlag = true; - - var regenerateThumbnails = function (dialog) { - - return $.ajax({ - method: 'POST', - url: ajaxurl, - dataType: 'json', - async: false, - data: { - action: 'wpp_images_action', - image_action: 'regenerate_thumbnails', - remove_flag: removeFlag, - nonce: WPP.nonce - } - }).done(function (response) { - - dialog.setContent('
' + response.percent + '%

'); - dialog.setContentAppend('
' + response.info + '
'); - - removeFlag = false; - - if (response.process) { - regenerateThumbnails(dialog) - } - - - }).fail(function (e) { - - console.log(e.statusText, e.responseText) - - dialog.setTitle('Error'); - dialog.setContent('
' + WPP.lang.something_went_wrong + '
'); - - }); - - }; - - $.confirm({ - title: title, - content: '
' + WPP.lang.regenerate_thumbs_info + '
', - buttons: { - Confirm: { - action: function () { - // hm.. - $('.jconfirm-content-pane').removeClass('no-scroll').removeAttr('style') - this.buttons.Confirm.hide(); - this.buttons.Cancel.hide(); - this.setTitle(WPP.lang.regenerate_thumbs); - this.setContent('
0%

'); - return regenerateThumbnails(this); - } - }, - Cancel: function () { } - } - }); - - }); - - - /** - * Perform database actions - */ - $(document).on('click', '.wpp-db-action', function (e) { - - e.preventDefault(); - - var action = $(this).data('action'); - var description = $(this).data('description'); - var count = $(this).data('count'); - - $.confirm({ - content: description, - buttons: { - Confirm: function () { - - $('body').append('
'); - - $.ajax({ - method: 'POST', - url: ajaxurl, - dataType: 'json', - data: { - action: 'wpp_clean_database', - db_action: action, - nonce: WPP.nonce - } - }).done(function () { - - $('#wpp_overlay').remove(); - - if (action == 'all') { - $('.wpp-db-count').text('0'); - } else { - var prev = $('#wpp-all-count').text(); - $('#wpp-' + action + '-count').text('0'); - $('#wpp-all-count').text(parseInt(prev) - parseInt(count)) - } - - }); - - }, - Cancel: function () { } - } - }); - - - }); - - - /** - * Load settings - */ - $(document).on('click', '.wpp-load-settings', function (e) { - - e.preventDefault(); - - var href = $(this).attr('href'); - var description = $(this).data('description'); - - $.confirm({ - content: description, - buttons: { - Confirm: function () { - window.location.href = href; - }, - Cancel: function () { - } - } - }); - - }); - - /** - * Show hide add-on settings - */ - $(document).on('click', '.wpp-addon-settings-toggle', function (e) { - - e.preventDefault(); - - var container = $(this).data('addon-settings'); - - $('[data-addon-settings-content="' + container + '"]').slideToggle(); - - }); - - - /** - * Add input element - */ - $(document).on('click', '[data-add-input]', function (e) { - - e.preventDefault(); - - var name = $(this).data('add-input'); - var info = $(this).attr('data-info'); - var placeholder = $(this).attr('data-placeholder') || ''; - var container = $(this).data('container'); - var suggest = $(this).data('suggest'); - - var input = '
'; - input += '   '; - input += '' + WPP.lang.remove + ''; - input += '
'; - - $(container).append(input); - - if (suggest) { - - $(container).find('.wpp-dynamic-input:last').autocomplete({ - source: WPP.autocomplete[suggest], - minLength: 2 - }); - } - - if (info && $('[data-info-name="' + name + '"]').length == 0) { - - if (info.indexOf('|') !== -1) { - - var notes = info.split('|'); - var output = ''; - - for (var i in notes) { - output += ' ' + notes[i] + ''; - } - - $(container).after('
' + output + '
'); - - } else { - $(container).after('
' + info + '
'); - } - - } - - }); - - /** - * Remove input element - */ - $(document).on('click', '.wpp-remove-input', function (e) { - - e.preventDefault(); - - $(this).parent().remove(); - - if ($('[data-dynamic-container="' + $(this).data('name') + '"]').length == 0) { - $('[data-info-name="' + $(this).data('name') + '"]').remove(); - } - - }); - - - /** - * Remove dismissible notice - */ - var notice = $('.wpp-notice'); - - if (notice.length && notice.hasClass('is-dismissible')) { - - window.setTimeout(function () { - notice.fadeOut(); - }, 5000); - - } - - - /** - * Autoload log content - */ - var log_textarea = $('.wpp-log-textarea'); - - if (log_textarea.length) { - - var interval = setInterval(function () { - - $.ajax({ - method: 'POST', - url: ajaxurl, - data: { - action: 'wpp_get_log_content', - nonce: WPP.nonce - } - }).done(function (data) { - log_textarea.val(data) - }).fail(function () { - clearInterval(interval); - }) - - }, 10000); - - } - -}); \ No newline at end of file diff --git a/assets/admin/app/App.jsx b/assets/admin/app/App.jsx new file mode 100644 index 0000000..82ae770 --- /dev/null +++ b/assets/admin/app/App.jsx @@ -0,0 +1,99 @@ +import { useEffect, useState } from '@wordpress/element'; +import { __ } from '@wordpress/i18n'; +import Tabs from './components/Tabs'; +import Toaster from './components/Toaster'; +import ConfirmDialog from './components/ConfirmDialog'; +import OverviewTab from './tabs/OverviewTab'; +import CacheTab from './tabs/CacheTab'; +import CssTab from './tabs/CssTab'; +import JsTab from './tabs/JsTab'; +import HtmlTab from './tabs/HtmlTab'; +import MediaTab from './tabs/MediaTab'; +import DatabaseTab from './tabs/DatabaseTab'; +import CdnTab from './tabs/CdnTab'; +import SettingsTab from './tabs/SettingsTab'; +import AddonsTab from './tabs/AddonsTab'; +import CloudflareTab from './tabs/CloudflareTab'; +import Placeholder from './tabs/Placeholder'; + +const config = window.WPP || {}; + +const COMPONENTS = { + overview: OverviewTab, + cache: CacheTab, + css: CssTab, + javascript: JsTab, + html: HtmlTab, + media: MediaTab, + database: DatabaseTab, + cdn: CdnTab, + settings: SettingsTab, + addons: AddonsTab, + cloudflare: CloudflareTab, +}; + +const BASE_TABS = [ + { id: 'overview', label: __( 'Overview', 'wpp' ) }, + { id: 'cache', label: __( 'Cache', 'wpp' ) }, + { id: 'css', label: __( 'CSS', 'wpp' ) }, + { id: 'javascript', label: __( 'JavaScript', 'wpp' ) }, + { id: 'html', label: __( 'HTML', 'wpp' ) }, + { id: 'media', label: __( 'Media', 'wpp' ) }, + { id: 'database', label: __( 'Database', 'wpp' ) }, + { id: 'cdn', label: __( 'CDN', 'wpp' ) }, + { id: 'settings', label: __( 'Settings', 'wpp' ) }, + { id: 'addons', label: __( 'Add-ons', 'wpp' ) }, +]; + +function visibleTabs() { + const tabs = [ ...BASE_TABS ]; + if ( config.settings && config.settings.cloudflare && config.settings.cloudflare.enabled ) { + tabs.push( { id: 'cloudflare', label: __( 'Cloudflare', 'wpp' ) } ); + } + return tabs; +} + +function initialTab( tabs ) { + const requested = new URLSearchParams( window.location.search ).get( 'tab' ); + return tabs.some( ( t ) => t.id === requested ) ? requested : 'overview'; +} + +export default function App() { + const [ tabs, setTabs ] = useState( visibleTabs ); + const [ active, setActive ] = useState( () => initialTab( visibleTabs() ) ); + + // A saved add-on toggle can add or remove a tab. + useEffect( () => { + const refresh = () => setTabs( visibleTabs() ); + window.addEventListener( 'wpp:settings-saved', refresh ); + return () => window.removeEventListener( 'wpp:settings-saved', refresh ); + }, [] ); + + const change = ( id ) => { + setActive( id ); + const url = new URL( window.location.href ); + url.searchParams.set( 'tab', id ); + window.history.replaceState( {}, '', url ); + }; + + const activeLabel = tabs.find( ( t ) => t.id === active )?.label; + const Active = COMPONENTS[ active ]; + + return ( +
+
+

{ __( 'WP Performance', 'wpp' ) }

+ v{ config.version } +
+ + + +
+ { Active ? : } +
+ + + +
+ ); +} diff --git a/assets/admin/app/api.js b/assets/admin/app/api.js new file mode 100644 index 0000000..787b563 --- /dev/null +++ b/assets/admin/app/api.js @@ -0,0 +1,21 @@ +import apiFetch from '@wordpress/api-fetch'; + +// api-fetch resolves the REST root and injects the nonce via middleware that WP +// registers when wp-api-fetch is enqueued. Paths are relative to /wp-json/. + +export function getSettings( group ) { + return apiFetch( { path: `/wpp/v1/settings/${ group }` } ); +} + +export function updateSettings( group, data ) { + return apiFetch( { + path: `/wpp/v1/settings/${ group }`, + method: 'PUT', + data, + } ); +} + +// Generic action helper for non-settings endpoints (added in later phases). +export function action( path, options = {} ) { + return apiFetch( { path: `/wpp/v1/${ path }`, ...options } ); +} diff --git a/assets/admin/app/app.scss b/assets/admin/app/app.scss new file mode 100644 index 0000000..a715504 --- /dev/null +++ b/assets/admin/app/app.scss @@ -0,0 +1,1097 @@ +:root { + --wpp-accent: #fc4213; + --wpp-accent-hover: #e2380f; + --wpp-text: #3c434a; + --wpp-heading: #1d2327; + --wpp-muted: #757575; + --wpp-border: #e2e4e7; + --wpp-border-strong: #c9ccd1; + --wpp-bg-side: #fafbfc; + --wpp-radius: 8px; + --wpp-radius-sm: 6px; +} + +.wpp-wrap { + margin: 16px 20px 40px 2px; +} + +.wpp-app { + // Interactive controls follow the admin colour scheme so they match the rest + // of wp-admin. Declared here rather than on :root because WordPress sets + // --wp-admin-theme-color on body, and a :root alias would resolve against an + // older fallback value instead. + --wpp-control: var( --wp-admin-theme-color, #3858e9 ); + --wpp-control-hover: var( --wp-admin-theme-color-darker-10, #2145e6 ); + + max-width: 1180px; + font-size: 14px; + line-height: 1.5; + color: var( --wpp-text ); + + * { + box-sizing: border-box; + } + + /* ---------- Header ---------- */ + &__header { + display: flex; + align-items: baseline; + gap: 10px; + margin: 6px 0 18px; + + h1 { + margin: 0; + padding: 0; + font-size: 23px; + font-weight: 600; + color: var( --wpp-heading ); + } + } + + &__version { + font-size: 12px; + font-weight: 600; + color: var( --wpp-muted ); + background: #f0f0f1; + border-radius: 20px; + padding: 2px 10px; + } + + /* ---------- Tabs ---------- */ + .wpp-tabs { + display: flex; + flex-wrap: wrap; + gap: 2px; + border-bottom: 1px solid var( --wpp-border ); + margin-bottom: -1px; + + &__tab { + appearance: none; + background: transparent; + border: 0; + border-bottom: 2px solid transparent; + padding: 12px 18px; + font-size: 13px; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.02em; + color: var( --wpp-muted ); + cursor: pointer; + transition: color 0.12s ease, border-color 0.12s ease; + + &:hover { + color: var( --wpp-heading ); + } + + &.is-active { + color: var( --wpp-control ); + border-bottom-color: var( --wpp-control ); + } + + &:focus-visible { + outline: 2px solid var( --wpp-control ); + outline-offset: -2px; + } + } + } + + /* ---------- Card / layout ---------- */ + .wpp-card { + margin-top: 20px; + background: #fff; + border: 1px solid var( --wpp-border ); + border-radius: var( --wpp-radius ); + box-shadow: 0 1px 2px rgba( 0, 0, 0, 0.04 ); + overflow: hidden; + } + + .wpp-two-col { + display: flex; + align-items: stretch; + + &__content { + flex: 1 1 auto; + min-width: 0; + padding: 24px 28px; + } + + &__side { + flex: 0 0 340px; + padding: 24px 24px; + background: var( --wpp-bg-side ); + border-left: 1px solid var( --wpp-border ); + } + + &--single .wpp-two-col__content { + max-width: 760px; + } + + /* Side column is narrow: stack field label above a full-width control. */ + &__side { + .wpp-field { + flex-direction: column; + gap: 6px; + padding: 12px 0; + } + + .wpp-field__label { + flex-basis: auto; + padding-top: 0; + } + + .wpp-input, + .wpp-select { + max-width: 100%; + } + } + } + + /* ---------- Section ---------- */ + .wpp-section { + // Note: must be `& + .wpp-section`, not `& + &`. With `&` resolving to the + // compound `.wpp-app .wpp-section`, `& + &` expands to a selector that needs + // a `.wpp-app` sibling and never matches. + & + .wpp-section { + margin-top: 26px; + padding-top: 22px; + border-top: 1px solid var( --wpp-border ); + } + + &__title { + margin: 0 0 14px; + font-size: 15px; + font-weight: 600; + color: var( --wpp-heading ); + } + } + + /* ---------- Field row ---------- */ + .wpp-field { + display: flex; + gap: 20px; + padding: 14px 0; + + & + .wpp-field { + border-top: 1px solid #f1f1f2; + } + + &__label { + flex: 0 0 210px; + font-weight: 600; + color: var( --wpp-heading ); + padding-top: 2px; + } + + &__control { + flex: 1 1 auto; + min-width: 0; + + > .wpp-toggle + .wpp-toggle { + margin-top: 12px; + } + } + + &__help { + margin: 8px 0 0; + font-size: 12.5px; + color: var( --wpp-muted ); + } + } + + .wpp-stack-top { + margin-top: 14px; + } + + /* ---------- Toggle switch ---------- */ + .wpp-toggle { + display: flex; + align-items: flex-start; + gap: 11px; + cursor: pointer; + + &.is-disabled { + opacity: 0.5; + cursor: not-allowed; + } + + &__switch { + position: relative; + flex: 0 0 auto; + width: 34px; + height: 20px; + + input { + position: absolute; + inset: 0; + width: 100%; + height: 100%; + margin: 0; + opacity: 0; + cursor: pointer; + } + } + + &__track { + display: block; + width: 34px; + height: 20px; + border-radius: 20px; + background: var( --wpp-border-strong ); + transition: background 0.15s ease; + } + + &__thumb { + position: absolute; + top: 3px; + left: 3px; + width: 14px; + height: 14px; + border-radius: 50%; + background: #fff; + box-shadow: 0 1px 2px rgba( 0, 0, 0, 0.25 ); + transition: transform 0.15s ease; + } + + input:checked ~ .wpp-toggle__track { + background: var( --wpp-control ); + } + + input:checked ~ .wpp-toggle__track .wpp-toggle__thumb { + transform: translateX( 14px ); + } + + input:focus-visible ~ .wpp-toggle__track { + box-shadow: 0 0 0 2px #fff, 0 0 0 4px var( --wpp-control ); + } + + &__text { + display: flex; + flex-direction: column; + padding-top: 1px; + } + + &__label { + color: var( --wpp-text ); + } + + &__help { + margin-top: 2px; + font-size: 12.5px; + color: var( --wpp-muted ); + } + } + + /* ---------- Inputs ---------- */ + .wpp-input { + width: 100%; + max-width: 420px; + height: 36px; + padding: 0 10px; + font-size: 14px; + color: var( --wpp-text ); + background: #fff; + border: 1px solid var( --wpp-border-strong ); + border-radius: var( --wpp-radius-sm ); + box-shadow: none; + transition: border-color 0.12s ease, box-shadow 0.12s ease; + + &:focus { + border-color: var( --wpp-control ); + box-shadow: 0 0 0 1px var( --wpp-control ); + outline: none; + } + + &--number { + width: 90px; + } + } + + .wpp-textarea { + height: auto; + max-width: 100%; + padding: 10px; + font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; + font-size: 12.5px; + line-height: 1.5; + resize: vertical; + } + + .wpp-log { + width: 100%; + white-space: pre; + color: var( --wpp-heading ); + background: #fbfbfc; + + &__actions { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; + margin-top: 8px; + + .wpp-field__help { + margin: 0; + } + } + } + + .wpp-select { + max-width: 240px; + padding-right: 28px; + } + + .wpp-inline { + display: flex; + align-items: center; + gap: 10px; + } + + /* ---------- Repeatable ---------- */ + .wpp-repeatable { + &__row { + display: flex; + align-items: center; + gap: 8px; + margin-bottom: 8px; + } + + &__remove { + display: inline-flex; + align-items: center; + justify-content: center; + width: 30px; + height: 30px; + flex: 0 0 auto; + border: 1px solid var( --wpp-border ); + border-radius: var( --wpp-radius-sm ); + background: #fff; + color: var( --wpp-muted ); + cursor: pointer; + + &:hover { + color: #b32d0f; + border-color: #f0b8ab; + background: #fdf2ef; + } + } + + &__add { + margin-top: 2px; + } + } + + /* ---------- Buttons ---------- */ + .wpp-btn { + display: inline-flex; + align-items: center; + gap: 6px; + height: 36px; + padding: 0 16px; + font-size: 13px; + font-weight: 600; + border-radius: var( --wpp-radius-sm ); + border: 1px solid transparent; + cursor: pointer; + transition: background 0.12s ease, border-color 0.12s ease, opacity 0.12s ease; + + &--primary { + background: var( --wpp-control ); + color: #fff; + + &:hover:not( :disabled ) { + background: var( --wpp-control-hover ); + } + + &:disabled { + opacity: 0.5; + cursor: default; + } + } + + &--ghost { + background: #fff; + border-color: var( --wpp-border-strong ); + color: var( --wpp-text ); + + &:hover { + border-color: var( --wpp-control ); + color: var( --wpp-control ); + } + } + + &--danger { + background: #b32d0f; + color: #fff; + + &:hover:not( :disabled ) { + background: #8f2409; + } + } + + &--sm { + height: 30px; + padding: 0 12px; + font-size: 12px; + } + + &:disabled { + opacity: 0.5; + cursor: default; + } + } + + /* ---------- Settings history / restore points ---------- */ + .wpp-history { + margin: 0; + padding: 0; + list-style: none; + + &__item { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; + padding: 12px 0; + border-bottom: 1px solid var( --wpp-border ); + + &:first-child { + padding-top: 0; + } + + &:last-child { + border-bottom: 0; + } + } + + &__meta { + display: flex; + flex-direction: column; + gap: 2px; + min-width: 0; + + strong { + font-size: 13px; + color: var( --wpp-heading ); + } + + span { + font-size: 12px; + color: var( --wpp-muted ); + } + } + } + + /* ---------- Save bar ---------- */ + .wpp-savebar { + margin-top: 26px; + padding-top: 20px; + border-top: 1px solid var( --wpp-border ); + } + + /* ---------- Placeholder ---------- */ + .wpp-placeholder { + padding: 60px 28px; + text-align: center; + color: var( --wpp-muted ); + } + + /* ---------- Cache statistics ---------- */ + .wpp-stats { + margin: 0 0 14px; + padding: 0; + list-style: none; + + li { + display: flex; + align-items: center; + justify-content: space-between; + padding: 7px 0; + border-bottom: 1px solid var( --wpp-border ); + font-size: 13px; + } + + strong { + color: var( --wpp-heading ); + } + + &__total { + border-bottom: 0 !important; + font-weight: 600; + } + } + + /* ---------- Overview / dashboard ---------- */ + .wpp-overview { + padding: 24px 28px; + + &__cards { + display: grid; + grid-auto-flow: column; + grid-auto-columns: minmax( 0, 1fr ); + gap: 16px; + margin-bottom: 26px; + } + } + + .wpp-stat-card { + display: flex; + flex-direction: column; + gap: 6px; + padding: 18px 20px; + border: 1px solid var( --wpp-border ); + border-radius: var( --wpp-radius-sm ); + background: #fff; + + &__label { + font-size: 12px; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.03em; + color: var( --wpp-muted ); + } + + &__value { + font-size: 24px; + font-weight: 600; + color: var( --wpp-heading ); + } + + &--action { + align-items: center; + justify-content: center; + background: var( --wpp-bg-side ); + } + } + + .wpp-presets { + display: grid; + grid-template-columns: repeat( 3, 1fr ); + gap: 16px; + margin-top: 14px; + } + + .wpp-preset { + display: flex; + flex-direction: column; + gap: 8px; + padding: 18px; + border: 1px solid var( --wpp-border ); + border-radius: var( --wpp-radius-sm ); + background: #fff; + + &__head { + display: flex; + align-items: center; + gap: 8px; + + strong { + font-size: 15px; + color: var( --wpp-heading ); + } + } + + &__badge { + font-size: 10px; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.04em; + color: var( --wpp-accent ); + background: rgba( 252, 66, 19, 0.1 ); + border-radius: 20px; + padding: 2px 8px; + } + + &__desc { + flex: 1; + margin: 0; + font-size: 12.5px; + color: var( --wpp-muted ); + line-height: 1.5; + } + + .wpp-btn { + align-self: flex-start; + margin-top: 4px; + } + } + + .wpp-feature-grid { + display: grid; + grid-template-columns: repeat( 3, 1fr ); + gap: 10px 16px; + margin: 0; + padding: 0; + list-style: none; + } + + .wpp-feature { + display: flex; + align-items: center; + gap: 10px; + font-size: 13px; + + &__icon { + display: inline-flex; + align-items: center; + justify-content: center; + width: 24px; + height: 24px; + border-radius: 50%; + flex-shrink: 0; + } + + &.is-on { + color: var( --wpp-heading ); + font-weight: 600; + + .wpp-feature__icon { + background: rgba( 26, 127, 71, 0.12 ); + color: #1a7f47; + } + } + + &.is-off { + color: var( --wpp-muted ); + + .wpp-feature__icon { + background: #f0f0f1; + color: var( --wpp-muted ); + } + } + } + + .wpp-health { + margin: 0; + padding: 0; + list-style: none; + + &__item { + display: flex; + align-items: flex-start; + gap: 12px; + padding: 12px 0; + border-bottom: 1px solid var( --wpp-border ); + + &:last-child { + border-bottom: 0; + } + + &.is-good .wpp-health__icon { + color: #1a7f47; + } + + &.is-warn .wpp-health__icon { + color: #b26a00; + } + + &.is-bad .wpp-health__icon { + color: #b32d0f; + } + } + + &__icon { + display: inline-flex; + margin-top: 1px; + flex-shrink: 0; + } + + &__text { + display: flex; + flex-direction: column; + gap: 2px; + + strong { + color: var( --wpp-heading ); + font-size: 13px; + } + + span { + color: var( --wpp-muted ); + font-size: 12.5px; + } + } + } + + /* ---------- Database cards ---------- */ + .wpp-db-grid { + display: grid; + grid-template-columns: repeat( 2, 1fr ); + gap: 16px; + } + + .wpp-db-card { + border: 1px solid var( --wpp-border ); + border-radius: var( --wpp-radius-sm ); + padding: 16px 18px; + background: #fff; + + &__head { + display: flex; + align-items: center; + justify-content: space-between; + } + + &__count { + font-size: 24px; + font-weight: 700; + color: var( --wpp-heading ); + line-height: 1; + } + + &__title { + margin: 12px 0 4px; + font-size: 14px; + color: var( --wpp-heading ); + } + + &__desc { + margin: 0 0 12px; + font-size: 12.5px; + color: var( --wpp-muted ); + } + } + + .wpp-db-footer { + display: flex; + align-items: center; + justify-content: space-between; + gap: 16px; + margin-top: 20px; + padding-top: 16px; + border-top: 1px solid var( --wpp-border ); + + .wpp-field__help { + margin: 0; + } + } + + /* ---------- File list table (CSS/JS) ---------- */ + .wpp-fl { + width: 100%; + border-collapse: collapse; + font-size: 13px; + + th { + padding: 8px; + text-align: center; + font-size: 11px; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.02em; + color: var( --wpp-muted ); + border-bottom: 1px solid var( --wpp-border ); + } + + th:first-child { + text-align: left; + } + + td { + padding: 8px; + border-bottom: 1px solid #f1f1f2; + vertical-align: middle; + } + + &__file { + font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; + font-size: 12px; + color: var( --wpp-text ); + word-break: break-all; + } + + &__check { + width: 74px; + text-align: center; + } + + &__check .wpp-toggle { + justify-content: center; + } + + &__check--na { + color: #c9ccd1; + } + + &__group td { + background: var( --wpp-bg-side ); + font-size: 11px; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.03em; + color: var( --wpp-heading ); + } + + &__bulk td { + background: #fff7f4; + font-weight: 600; + } + + &__sub td { + background: var( --wpp-bg-side ); + } + + &__position { + display: flex; + flex-direction: column; + gap: 10px; + padding: 4px 0; + } + } + + .wpp-fl__actions { + margin-top: 16px; + } + + /* ---------- Image sizes ---------- */ + .wpp-sizes { + &__table { + width: 100%; + border-collapse: collapse; + font-size: 13px; + margin-bottom: 12px; + } + + &__table th { + padding: 6px; + text-align: left; + font-size: 11px; + text-transform: uppercase; + color: var( --wpp-muted ); + border-bottom: 1px solid var( --wpp-border ); + } + + &__table td { + padding: 6px; + border-bottom: 1px solid #f1f1f2; + } + + &__remove { + border: 0; + background: transparent; + cursor: pointer; + color: var( --wpp-muted ); + font-size: 18px; + line-height: 1; + + &:hover { + color: #b32d0f; + } + } + + &__form { + display: flex; + flex-wrap: wrap; + gap: 8px; + align-items: center; + + .wpp-input { + width: auto; + flex: 1 1 110px; + } + } + + &__crop { + display: inline-flex; + align-items: center; + gap: 6px; + font-size: 13px; + } + + &__actions, + &__regen { + margin-top: 12px; + display: flex; + gap: 8px; + } + } + + /* ---------- Add-ons ---------- */ + .wpp-addons { + display: grid; + grid-template-columns: repeat( 3, 1fr ); + gap: 16px; + } + + .wpp-addon { + border: 1px solid var( --wpp-border ); + border-radius: var( --wpp-radius-sm ); + padding: 18px; + + &__head { + display: flex; + align-items: center; + justify-content: space-between; + } + + &__head h3 { + margin: 0; + font-size: 15px; + color: var( --wpp-heading ); + } + + &__desc { + margin: 10px 0 14px; + font-size: 12.5px; + color: var( --wpp-muted ); + } + + &__field { + margin-top: 10px; + } + + &__field label { + display: block; + margin-bottom: 4px; + font-size: 12px; + color: var( --wpp-muted ); + } + } +} + +@media ( max-width: 960px ) { + .wpp-app .wpp-addons { + grid-template-columns: 1fr; + } +} + +@media ( max-width: 782px ) { + .wpp-app .wpp-db-grid { + grid-template-columns: 1fr; + } +} + +/* ---------- Toaster (outside flow) ---------- */ +.wpp-modal { + position: fixed; + inset: 0; + z-index: 100001; + display: flex; + align-items: center; + justify-content: center; + padding: 24px; + background: rgba( 0, 0, 0, 0.45 ); + animation: wpp-modal-fade 0.12s ease; + + &__box { + width: 100%; + max-width: 460px; + padding: 24px 26px 20px; + background: #fff; + border-radius: var( --wpp-radius ); + box-shadow: 0 12px 40px rgba( 0, 0, 0, 0.25 ); + animation: wpp-modal-in 0.14s ease; + } + + &__title { + margin: 0 0 8px; + padding: 0; + font-size: 17px; + font-weight: 600; + color: var( --wpp-heading ); + } + + &__body { + margin: 0; + font-size: 14px; + line-height: 1.55; + color: var( --wpp-text ); + } + + &__actions { + display: flex; + justify-content: flex-end; + gap: 10px; + margin-top: 22px; + } +} + +@keyframes wpp-modal-fade { + from { opacity: 0; } + to { opacity: 1; } +} + +@keyframes wpp-modal-in { + from { opacity: 0; transform: translateY( 8px ) scale( 0.98 ); } + to { opacity: 1; transform: none; } +} + +.wpp-toaster { + position: fixed; + right: 24px; + bottom: 24px; + z-index: 100000; + display: flex; + flex-direction: column; + gap: 10px; +} + +.wpp-toast { + min-width: 240px; + max-width: 360px; + padding: 12px 16px; + font-size: 13.5px; + color: #fff; + border-radius: var( --wpp-radius-sm ); + box-shadow: 0 6px 20px rgba( 0, 0, 0, 0.18 ); + animation: wpp-toast-in 0.18s ease; + + &--success { + background: #1a7f47; + } + + &--error { + background: #b32d0f; + } +} + +@keyframes wpp-toast-in { + from { + opacity: 0; + transform: translateY( 8px ); + } + to { + opacity: 1; + transform: translateY( 0 ); + } +} + +/* ---------- Responsive ---------- */ +@media ( max-width: 960px ) { + .wpp-app .wpp-two-col { + flex-direction: column; + + &__side { + flex-basis: auto; + border-left: 0; + border-top: 1px solid var( --wpp-border ); + } + } + + .wpp-app .wpp-field { + flex-direction: column; + gap: 8px; + + &__label { + flex-basis: auto; + } + } + + .wpp-app .wpp-overview__cards { + grid-auto-flow: row; + grid-auto-columns: auto; + grid-template-columns: repeat( 2, 1fr ); + } + + .wpp-app .wpp-feature-grid, + .wpp-app .wpp-presets { + grid-template-columns: repeat( 2, 1fr ); + } +} + +@media ( max-width: 600px ) { + .wpp-app .wpp-overview__cards, + .wpp-app .wpp-feature-grid, + .wpp-app .wpp-presets { + grid-template-columns: 1fr; + } +} diff --git a/assets/admin/app/components/ConfirmDialog.jsx b/assets/admin/app/components/ConfirmDialog.jsx new file mode 100644 index 0000000..2d28dbc --- /dev/null +++ b/assets/admin/app/components/ConfirmDialog.jsx @@ -0,0 +1,117 @@ +import { useEffect, useRef, useState } from '@wordpress/element'; +import { __ } from '@wordpress/i18n'; +import { subscribe } from '../lib/confirm'; + +export default function ConfirmDialog() { + const [ request, setRequest ] = useState( null ); + const dialogRef = useRef( null ); + const confirmRef = useRef( null ); + const openerRef = useRef( null ); + + useEffect( () => subscribe( ( entry ) => { + openerRef.current = document.activeElement; + setRequest( entry ); + } ), [] ); + + const close = ( answer ) => { + if ( request ) { + request.resolve( answer ); + } + setRequest( null ); + + // Send focus back where it came from, or the trigger silently loses it. + if ( openerRef.current && typeof openerRef.current.focus === 'function' ) { + openerRef.current.focus(); + } + openerRef.current = null; + }; + + useEffect( () => { + if ( ! request ) { + return; + } + + confirmRef.current?.focus(); + + const onKeyDown = ( event ) => { + if ( event.key === 'Escape' ) { + event.preventDefault(); + close( false ); + return; + } + + if ( event.key !== 'Tab' ) { + return; + } + + // Keep focus inside the dialog while it is open. + const focusable = dialogRef.current?.querySelectorAll( 'button, [href], input, select, textarea' ); + if ( ! focusable || focusable.length === 0 ) { + return; + } + const first = focusable[ 0 ]; + const last = focusable[ focusable.length - 1 ]; + + if ( event.shiftKey && document.activeElement === first ) { + event.preventDefault(); + last.focus(); + } else if ( ! event.shiftKey && document.activeElement === last ) { + event.preventDefault(); + first.focus(); + } + }; + + document.addEventListener( 'keydown', onKeyDown ); + return () => document.removeEventListener( 'keydown', onKeyDown ); + }, [ request ] ); + + if ( ! request ) { + return null; + } + + const title = request.title || __( 'Are you sure?', 'wpp' ); + + return ( +
{ + if ( e.target === e.currentTarget ) { + close( false ); + } + } } + > +
+

+ { title } +

+

+ { request.message } +

+
+ + +
+
+
+ ); +} diff --git a/assets/admin/app/components/Field.jsx b/assets/admin/app/components/Field.jsx new file mode 100644 index 0000000..c115033 --- /dev/null +++ b/assets/admin/app/components/Field.jsx @@ -0,0 +1,11 @@ +export default function Field( { label, children, help } ) { + return ( +
+ { label &&
{ label }
} +
+ { children } + { help &&

{ help }

} +
+
+ ); +} diff --git a/assets/admin/app/components/FileListTable.jsx b/assets/admin/app/components/FileListTable.jsx new file mode 100644 index 0000000..b531613 --- /dev/null +++ b/assets/admin/app/components/FileListTable.jsx @@ -0,0 +1,147 @@ +import { Fragment } from '@wordpress/element'; +import { __ } from '@wordpress/i18n'; +import Toggle from './fields/Toggle'; +import SelectField from './fields/SelectField'; +import RepeatableInput from './fields/RepeatableInput'; + +const GROUPS = [ + [ 'theme', __( 'Theme', 'wpp' ) ], + [ 'plugin', __( 'Plugins', 'wpp' ) ], + [ 'external', __( 'External', 'wpp' ) ], +]; + +const POSITIONS = [ + { value: 'everywhere', label: __( 'Everywhere', 'wpp' ) }, + { value: 'selected', label: __( 'Only on selected URLs', 'wpp' ) }, + { value: 'except', label: __( 'Everywhere except selected URLs', 'wpp' ) }, +]; + +function shortLabel( url ) { + try { + return new URL( url ).pathname; + } catch ( e ) { + return url; + } +} + +export default function FileListTable( { files, draft, setIn } ) { + const present = GROUPS.filter( ( [ g ] ) => ( files[ g ] || [] ).length > 0 ); + const localFiles = [ 'theme', 'plugin' ].flatMap( ( g ) => files[ g ] || [] ); + const everyFile = GROUPS.flatMap( ( [ g ] ) => files[ g ] || [] ); + + if ( present.length === 0 ) { + return ( +

+ { __( + 'No files collected yet. Enable caching or an optimization, visit your site, then choose "Update files list".', + 'wpp' + ) } +

+ ); + } + + const map = ( col ) => draft[ col ] || {}; + + const setExclusive = ( url, col, value ) => { + if ( value && col === 'combine' ) { + setIn( 'inline', url, false ); + } + if ( value && col === 'inline' ) { + setIn( 'combine', url, false ); + } + setIn( col, url, value ); + }; + + const targetsFor = ( col ) => ( col === 'disable' ? everyFile : localFiles ); + const allOn = ( col ) => { + const t = targetsFor( col ); + return t.length > 0 && t.every( ( u ) => !! map( col )[ u ] ); + }; + const bulk = ( col, value ) => targetsFor( col ).forEach( ( u ) => setExclusive( u, col, value ) ); + + const checkCell = ( url, col, enabled ) => + enabled ? ( + + setExclusive( url, col, v ) } /> + + ) : ( + - + ); + + return ( + + + + + + + + + + + + + + { [ 'minify', 'inline', 'combine', 'disable' ].map( ( col ) => ( + + ) ) } + + + { present.map( ( [ g, groupLabel ] ) => ( + + + + + { ( files[ g ] || [] ).map( ( url ) => { + const local = g !== 'external'; + const disabled = !! map( 'disable' )[ url ]; + const position = map( 'disable_position' )[ url ] || 'everywhere'; + return ( + + + + { checkCell( url, 'minify', local ) } + { checkCell( url, 'inline', local ) } + { checkCell( url, 'combine', local ) } + { checkCell( url, 'disable', true ) } + + { disabled && ( + + + + ) } + + ); + } ) } + + ) ) } + +
{ __( 'File', 'wpp' ) }{ __( 'Minify', 'wpp' ) }{ __( 'Inline', 'wpp' ) }{ __( 'Combine', 'wpp' ) }{ __( 'Disable', 'wpp' ) }
{ __( 'Apply to all', 'wpp' ) } + bulk( col, v ) } /> +
{ groupLabel }
+ { shortLabel( url ) } +
+
+ setIn( 'disable_position', url, v ) } + /> + { position === 'selected' && ( + setIn( 'disable_selected', url, v ) } + addLabel={ __( 'Add URL', 'wpp' ) } + /> + ) } + { position === 'except' && ( + setIn( 'disable_except', url, v ) } + addLabel={ __( 'Add URL', 'wpp' ) } + /> + ) } +
+
+ ); +} diff --git a/assets/admin/app/components/ImageSizes.jsx b/assets/admin/app/components/ImageSizes.jsx new file mode 100644 index 0000000..0e4d0db --- /dev/null +++ b/assets/admin/app/components/ImageSizes.jsx @@ -0,0 +1,199 @@ +import { useEffect, useState } from '@wordpress/element'; +import { __ } from '@wordpress/i18n'; +import { confirm } from '../lib/confirm'; +import { action } from '../api'; +import { toast } from '../lib/toast'; + +const EMPTY = { name: '', width: '', height: '', crop: false }; + +export default function ImageSizes() { + const [ sizes, setSizes ] = useState( [] ); + const [ adding, setAdding ] = useState( false ); + const [ form, setForm ] = useState( EMPTY ); + const [ regen, setRegen ] = useState( null ); + + useEffect( () => { + action( 'images/sizes' ).then( setSizes ).catch( () => {} ); + }, [] ); + + const add = async () => { + if ( ! form.name || ! form.width || ! form.height ) { + return; + } + try { + const next = await action( 'images/sizes', { + method: 'POST', + data: { + name: form.name, + width: Number( form.width ), + height: Number( form.height ), + crop: form.crop, + }, + } ); + setSizes( next ); + setForm( EMPTY ); + setAdding( false ); + toast( __( 'Image size added.', 'wpp' ), 'success' ); + } catch ( e ) { + toast( e.message || __( 'Could not add size.', 'wpp' ), 'error' ); + } + }; + + const remove = async ( name ) => { + // eslint-disable-next-line no-alert + const ok = await confirm( { + title: __( 'Remove image size', 'wpp' ), + message: __( 'New uploads will no longer be generated at this size.', 'wpp' ), + confirm: __( 'Remove', 'wpp' ), + destructive: true, + } ); + if ( ! ok ) { + return; + } + try { + setSizes( await action( 'images/sizes/remove', { method: 'POST', data: { name } } ) ); + } catch ( e ) { + toast( e.message || __( 'Could not remove size.', 'wpp' ), 'error' ); + } + }; + + const restore = async () => { + // eslint-disable-next-line no-alert + const ok = await confirm( { + title: __( 'Restore defaults', 'wpp' ), + message: __( 'This restores the WordPress default image sizes and discards your changes here.', 'wpp' ), + confirm: __( 'Restore', 'wpp' ), + } ); + if ( ! ok ) { + return; + } + setSizes( await action( 'images/sizes/restore', { method: 'POST' } ) ); + toast( __( 'Defaults restored.', 'wpp' ), 'success' ); + }; + + const regenerate = async () => { + // eslint-disable-next-line no-alert + const ok = await confirm( { + title: __( 'Regenerate thumbnails', 'wpp' ), + message: __( 'Every image is processed again. This may take a while on large media libraries.', 'wpp' ), + confirm: __( 'Regenerate', 'wpp' ), + } ); + if ( ! ok ) { + return; + } + let offset = 0; + setRegen( { processed: 0, total: 0 } ); + try { + for ( ;; ) { + const r = await action( 'images/regenerate', { + method: 'POST', + data: { offset, limit: 5 }, + } ); + setRegen( { processed: r.processed, total: r.total } ); + offset = r.processed; + if ( r.done ) { + break; + } + } + toast( __( 'Thumbnails regenerated.', 'wpp' ), 'success' ); + } catch ( e ) { + toast( e.message || __( 'Regeneration failed.', 'wpp' ), 'error' ); + } finally { + setTimeout( () => setRegen( null ), 1500 ); + } + }; + + const pct = regen && regen.total ? Math.round( ( regen.processed / regen.total ) * 100 ) : 0; + + return ( +
+ + + + + + + + + + + { sizes.map( ( s ) => ( + + + + + + + + ) ) } + +
{ __( 'Name', 'wpp' ) }{ __( 'W', 'wpp' ) }{ __( 'H', 'wpp' ) }{ __( 'Crop', 'wpp' ) } +
{ s.name }{ s.width }{ s.height }{ s.crop ? __( 'Yes', 'wpp' ) : '-' } + +
+ + { adding ? ( +
+ setForm( { ...form, name: e.target.value } ) } + /> + setForm( { ...form, width: e.target.value } ) } + /> + setForm( { ...form, height: e.target.value } ) } + /> + + + +
+ ) : ( +
+ + +
+ ) } + +
+ +
+
+ ); +} diff --git a/assets/admin/app/components/SaveButton.jsx b/assets/admin/app/components/SaveButton.jsx new file mode 100644 index 0000000..f85c9b8 --- /dev/null +++ b/assets/admin/app/components/SaveButton.jsx @@ -0,0 +1,16 @@ +import { __ } from '@wordpress/i18n'; + +export default function SaveButton( { onSave, isDirty, saving } ) { + return ( +
+ +
+ ); +} diff --git a/assets/admin/app/components/Section.jsx b/assets/admin/app/components/Section.jsx new file mode 100644 index 0000000..b050dd9 --- /dev/null +++ b/assets/admin/app/components/Section.jsx @@ -0,0 +1,8 @@ +export default function Section( { title, children } ) { + return ( +
+ { title &&

{ title }

} +
{ children }
+
+ ); +} diff --git a/assets/admin/app/components/Tabs.jsx b/assets/admin/app/components/Tabs.jsx new file mode 100644 index 0000000..86b08e6 --- /dev/null +++ b/assets/admin/app/components/Tabs.jsx @@ -0,0 +1,18 @@ +export default function Tabs( { tabs, active, onChange } ) { + return ( + + ); +} diff --git a/assets/admin/app/components/Toaster.jsx b/assets/admin/app/components/Toaster.jsx new file mode 100644 index 0000000..43082f2 --- /dev/null +++ b/assets/admin/app/components/Toaster.jsx @@ -0,0 +1,28 @@ +import { useEffect, useState } from '@wordpress/element'; +import { subscribe } from '../lib/toast'; + +export default function Toaster() { + const [ items, setItems ] = useState( [] ); + + useEffect( + () => + subscribe( ( t ) => { + setItems( ( cur ) => [ ...cur, t ] ); + setTimeout( + () => setItems( ( cur ) => cur.filter( ( x ) => x.id !== t.id ) ), + 4000 + ); + } ), + [] + ); + + return ( +
+ { items.map( ( t ) => ( +
+ { t.message } +
+ ) ) } +
+ ); +} diff --git a/assets/admin/app/components/TwoColumn.jsx b/assets/admin/app/components/TwoColumn.jsx new file mode 100644 index 0000000..a893c79 --- /dev/null +++ b/assets/admin/app/components/TwoColumn.jsx @@ -0,0 +1,8 @@ +export default function TwoColumn( { children, side } ) { + return ( +
+
{ children }
+ { side && } +
+ ); +} diff --git a/assets/admin/app/components/fields/NumberField.jsx b/assets/admin/app/components/fields/NumberField.jsx new file mode 100644 index 0000000..09eff42 --- /dev/null +++ b/assets/admin/app/components/fields/NumberField.jsx @@ -0,0 +1,17 @@ +export default function NumberField( { value, onChange, min = 1, max, step = 1, disabled = false } ) { + return ( + { + const v = e.target.value; + onChange( v === '' ? '' : Number( v ) ); + } } + /> + ); +} diff --git a/assets/admin/app/components/fields/RepeatableInput.jsx b/assets/admin/app/components/fields/RepeatableInput.jsx new file mode 100644 index 0000000..c67d0ae --- /dev/null +++ b/assets/admin/app/components/fields/RepeatableInput.jsx @@ -0,0 +1,49 @@ +import { __ } from '@wordpress/i18n'; +import { Plus, X } from 'lucide-react'; + +/** + * Edits an array of strings as a list of text inputs with add/remove. + */ +export default function RepeatableInput( { + value = [], + onChange, + placeholder = '', + addLabel = __( 'Add', 'wpp' ), +} ) { + const rows = Array.isArray( value ) ? value : []; + + const update = ( idx, val ) => { + const next = rows.slice(); + next[ idx ] = val; + onChange( next ); + }; + const remove = ( idx ) => onChange( rows.filter( ( _, i ) => i !== idx ) ); + const add = () => onChange( [ ...rows, '' ] ); + + return ( +
+ { rows.map( ( row, idx ) => ( +
+ update( idx, e.target.value ) } + /> + +
+ ) ) } + +
+ ); +} diff --git a/assets/admin/app/components/fields/SelectField.jsx b/assets/admin/app/components/fields/SelectField.jsx new file mode 100644 index 0000000..3a7256c --- /dev/null +++ b/assets/admin/app/components/fields/SelectField.jsx @@ -0,0 +1,16 @@ +export default function SelectField( { value, onChange, options, disabled = false } ) { + return ( + + ); +} diff --git a/assets/admin/app/components/fields/TextField.jsx b/assets/admin/app/components/fields/TextField.jsx new file mode 100644 index 0000000..861d521 --- /dev/null +++ b/assets/admin/app/components/fields/TextField.jsx @@ -0,0 +1,32 @@ +export default function TextField( { + value, + onChange, + placeholder = '', + type = 'text', + disabled = false, + multiline = false, + rows = 6, +} ) { + if ( multiline ) { + return ( + -
- - -
- - - id="wpp-get-critical-css" data-wpp-toggle="css-path"> - - -
- - - - - -
- -

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

- - - -
- -
- - - -


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

- -
- - - - - - - - - - - - - - - -
DNS PrefetchPreconnect
- - form="wpp-settings" /> - - - form="wpp-settings" /> -
-
- - - -
- - - -
- -

- -
- -
- - - -
- - - - -
- -   - - - -
- - - - - -
-   - -
- - -
- - -
- */ ?> - - - - -
-
- - - - - - - - -
- - - - - - \ No newline at end of file diff --git a/includes/admin/database.php b/includes/admin/database.php deleted file mode 100644 index 692e77a..0000000 --- a/includes/admin/database.php +++ /dev/null @@ -1,225 +0,0 @@ - - - - -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - () - - - -
- - - -
- - - - - - () - - - -
- - - -
- - - - - - () - - - -
- - - -
- - - - - () - - - -
- - - -
- - - - - - () - - - -
- - - -
- - - - - - () - - - -
- - - -
- -

- - - -
- - - - - () - - - -
- -
- -

- -
- -
    -
  • - - -


    - : - - -
  • -
- - -
- -
\ No newline at end of file diff --git a/includes/admin/html.php b/includes/admin/html.php deleted file mode 100644 index 6669226..0000000 --- a/includes/admin/html.php +++ /dev/null @@ -1,169 +0,0 @@ - - -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - -

- - - -
- - -

- -
- -

- - -
- - -

- -
- - -

- -
- -
- - - -

- -
- -
- - - - -
- -

- -
- - - -
- - - - -
- -   - - - -
- - - - - -
-   - -
- - -
- - -
- - - - -
-
- - - - - - - - -
- - - - -
- -
\ No newline at end of file diff --git a/includes/admin/includes/.htaccess b/includes/admin/includes/.htaccess deleted file mode 100644 index 14249c5..0000000 --- a/includes/admin/includes/.htaccess +++ /dev/null @@ -1 +0,0 @@ -Deny from all \ No newline at end of file diff --git a/includes/admin/includes/external_files.php b/includes/admin/includes/external_files.php deleted file mode 100644 index 7285b69..0000000 --- a/includes/admin/includes/external_files.php +++ /dev/null @@ -1,159 +0,0 @@ - - - - - - - - - - - - - - -
- - - -
- - - - $urls ): ?> - - - - - -
- -   - - - - - -
- - - - - - - - $urls ): ?> - - - - - -
- -   - - - - - -
- - - - - - -
- - - - - - - - - - - - - - - -
- - - - - - - - form="wpp-settings" /> - - - - - - - - - - \ No newline at end of file diff --git a/includes/admin/includes/index.php b/includes/admin/includes/index.php deleted file mode 100644 index e71af0e..0000000 --- a/includes/admin/includes/index.php +++ /dev/null @@ -1 +0,0 @@ - - - - - - - - - - - - - - - -
- - - -
- - - - $urls ): ?> - - - - - -
- -   - - - -
- - - - - - - - $urls ): ?> - - - - - -
- -   - - - -
- - - - - -
- - - - - - - - - - - - - - - -
- - - - - - - - - data-wpp-group="-minify" - name="_minify[]" - form="wpp-settings" /> - - - - - - - - - - - - form="wpp-settings" /> - - - - - - - - - - - - form="wpp-settings" /> - - - - - - - - - - - form="wpp-settings" /> - - - - - - - - - \ No newline at end of file diff --git a/includes/admin/index.php b/includes/admin/index.php deleted file mode 100644 index e71af0e..0000000 --- a/includes/admin/index.php +++ /dev/null @@ -1 +0,0 @@ - - -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 'js', - 'list' => $theme_files, - 'minified' => $minified, - 'combined' => $combined, - 'inlined' => $inlined, - 'disabled' => $disabled, - 'disabled_positions' => $disabled_positions, - ] ); - - ?> - - - - - - - - - - 'js', - 'list' => $plugin_files, - 'minified' => $minified, - 'combined' => $combined, - 'inlined' => $inlined, - 'disabled' => $disabled, - 'disabled_positions' => $disabled_positions, - ] ); - - ?> - - - - - - - - - - - 'js', - 'list' => $external_list, - 'disabled' => $disabled, - 'disabled_positions' => $disabled_positions, - ] ); - - ?> - - - - - -

- -
- - - -

- - - - - - - - - -

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

- -
- - - - - -

- - - -

- -
- -
- -

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

- -
- -

- -
- - - - - - - - - - - - - - - -
DNS PrefetchPreconnect
- - form="wpp-settings" /> - - - form="wpp-settings" /> -
-
- - - -
- - - -
- -

- -
- -
- - - -
- - - - -
- -   - - - -
- - - - - -
-   - -
- - -
- - -
- */ ?> - - - - -
-
- - - - - - - - -
- - - - - -
- -
\ No newline at end of file diff --git a/includes/admin/media.php b/includes/admin/media.php deleted file mode 100644 index 5d4d79e..0000000 --- a/includes/admin/media.php +++ /dev/null @@ -1,409 +0,0 @@ - - -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

- - -

- - -
- -
- -

- -
- - - -

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

- - - -
- - -
-   - -
- - - - -
- - : #my-container-id -
-
- - - -
- - -
- - - -

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

- - -

- - -
- - - -

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

- -
- -
- - - -

- -

- -
- - - -

- -
- - -

- -

- -
- - - -

- -
- -
- -

- -

- -
- - - - - - - - - - - $data ): ?> - - - - - - - - - -
- - - - - - - - - px - - - - - px - - - - - - - - - x - -
- -
- - - -
- -
- - -
- - -
- -
- - -
- -
\ No newline at end of file diff --git a/includes/admin/metabox.php b/includes/admin/metabox.php deleted file mode 100644 index 9a3487b..0000000 --- a/includes/admin/metabox.php +++ /dev/null @@ -1,332 +0,0 @@ - - - -
- -
- -
- - -
- - - -
- - -
- - - -
- -
- - - -
- - -
- - - -
- - -
- - - -
diff --git a/includes/admin/settings.php b/includes/admin/settings.php deleted file mode 100644 index 0f60638..0000000 --- a/includes/admin/settings.php +++ /dev/null @@ -1,135 +0,0 @@ - - -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-

-
- -
- - - -
-

-
- - - -
- -
-

-
- -

- -
- - -
- -

- - - - - - - -

- -
- -
- -

- -
- - - -
    - $settings ): - - if( $i >= 5 ) { - unlink( $settings ); - continue; - } - - $timestamp = filemtime( $settings ); - ?> -
  • - - - - - - -
  • - -
- - -
- - - - -
- -
\ No newline at end of file diff --git a/includes/advanced-cache.php b/includes/advanced-cache.php deleted file mode 100644 index 2588d2d..0000000 --- a/includes/advanced-cache.php +++ /dev/null @@ -1,221 +0,0 @@ - -* @package WPP -*/ - - -if ( ! empty( $_POST ) ) { - return false; -} - -// Get settings -$settings = _wpp_get_site_settings(); - -// Check if cache option is ON and cache is not disabled -if ( empty( $settings) || ! $settings[ 'cache' ] || $settings[ 'disable' ] ) - return false; - -// Get cache file and check if is readble -$cache_file = _wpp_get_cache_file( $settings ); - -if ( ! file_exists( $cache_file ) ) - return false; - -// Check excluded URLs -if ( ! empty( $settings[ 'exclude' ] ) ) { - - $current_url = _wpp_get_current_url(); - - $wildcards = [ - '{any}' => '[^/]+', - '{numbers}' => '[0-9]+', - '{letters}' => '[A-Za-z]+', - '{all}' => '.*' - ]; - - foreach( $settings[ 'exclude' ] as $excluded_url ) { - - $excluded_url = preg_quote( $excluded_url ); - - $excluded_url = str_replace( - array_keys( $wildcards ), - array_values( $wildcards ), - stripslashes( $excluded_url ) - ); - - // Try simple match first - if ( $excluded_url === $current_url ) { - return false; - } - - if ( preg_match( '#^' . $excluded_url . '$#', $current_url ) ) { - return false; - } - - } - -} - -// Check WP cookies -if ( ! empty( $_COOKIE ) ) { - - $cookies = '/^(wordpress_logged_in_|wp-postpass_|wptouch_switch_toggle|comment_author_|comment_author_email_)/'; - - foreach ( $_COOKIE as $cookie => $value ) { - if ( preg_match( $cookies, $cookie ) ) { - return false; - } - } - -} - -// Check if cache file has expired -if ( time() - intval( $settings[ 'expire' ] ) < filemtime( $cache_file ) ) { - - header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s', filemtime( $cache_file ) ) . ' GMT' ); - - // Getting If-Modified-Since headers - if ( function_exists( 'apache_request_headers' ) ) { - $apache_headers = apache_request_headers(); - $modified_since = isset( $apache_headers[ 'If-Modified-Since' ] ) ? $apache_headers[ 'If-Modified-Since' ] : ''; - $accept_encoding = isset( $headers[ 'Accept-Encoding' ] ) ? $headers[ 'Accept-Encoding' ] : ''; - } else { - $modified_since = isset( $_SERVER[ 'HTTP_IF_MODIFIED_SINCE' ] ) ? $_SERVER[ 'HTTP_IF_MODIFIED_SINCE' ] : '' ; - $accept_encoding = isset( $_SERVER[ 'HTTP_ACCEPT_ENCODING' ] ) ? $_SERVER[ 'HTTP_ACCEPT_ENCODING' ] : ''; - } - - // Check headers - if ( - ! empty( $modified_since ) - && ( strtotime( $modified_since ) === filemtime( $cache_file ) ) - ) { - // Client's cache is up to date - header( $_SERVER[ 'SERVER_PROTOCOL' ] . ' 304 Not Modified', true, 304 ); - exit; - } - - // Check if gzip is enabled - if ( - false !== strpos( $accept_encoding, 'gzip' ) - && function_exists( 'readgzfile' ) - && file_exists( $cache_file . '_gz' ) - ) { - readgzfile( $cache_file . '_gz' ); - } else { - include $cache_file; - } - - exit; - -} - - -/** - * Get cache file path - * - * @return string - */ -function _wpp_get_cache_file( $settings ) { - - $file = WP_CONTENT_DIR . '/cache/wpp-cache/' . $_SERVER[ 'HTTP_HOST' ] ; - - // Check if site is using permalinks - if ( $settings[ 'permalinks' ] ) { - - if ( ! empty( $_GET ) ) { - $uri = parse_url( $_SERVER[ 'REQUEST_URI' ] ); - $file .= $uri[ 'path' ] . md5( $uri[ 'query' ] ) . '.html'; - } else { - $file .= $_SERVER[ 'REQUEST_URI' ] . 'index.html'; - } - - } else { - $file .= '/' . md5( _wpp_get_current_url() ) . '.html'; - } - - // Is mobile device and mobile cache is ON - if ( $settings[ 'mobile_cache' ] && _wpp_is_mobile() ) { - $file .= '_mobile'; - } - - // Is AMP? Why not save this as mobile? - $amp_tag = defined( 'WPP_AMP_TAG' ) ? WPP_AMP_TAG : 'amp'; - - if ( - isset( $_GET[ $amp_tag ] ) - || preg_match( "/$amp_tag\/?$/", _wpp_get_current_url() ) - ) { - $file .= '_amp'; - } - - return $file; -} - - -/** - * Get site settings - * - * @return array - */ -function _wpp_get_site_settings() { - - $settings_file = sprintf( - '%s/%s.settings.json', - WP_CONTENT_DIR . '/cache/wpp-cache', - $_SERVER[ 'HTTP_HOST' ] - ); - - if ( file_exists( $settings_file ) ) { - return json_decode( - file_get_contents( $settings_file ), - true - ); - } - - return []; - -} - - -/** - * Check if is mobile device - * - * @return bool - */ -function _wpp_is_mobile() { - - if ( empty( $_SERVER[ 'HTTP_USER_AGENT' ] ) ) { - return false; - } - - if ( strpos( $_SERVER[ 'HTTP_USER_AGENT' ], 'Mobile' ) !== false - || strpos( $_SERVER[ 'HTTP_USER_AGENT' ], 'Android' ) !== false - || strpos( $_SERVER[ 'HTTP_USER_AGENT' ], 'Silk/' ) !== false - || strpos( $_SERVER[ 'HTTP_USER_AGENT' ], 'Kindle' ) !== false - || strpos( $_SERVER[ 'HTTP_USER_AGENT' ], 'BlackBerry' ) !== false - || strpos( $_SERVER[ 'HTTP_USER_AGENT' ], 'Opera Mini' ) !== false - || strpos( $_SERVER[ 'HTTP_USER_AGENT' ], 'Opera Mobi' ) !== false - ) { - return true; - } - - return false; -} - - -/** - * Get current URL - * - * @return string - */ -function _wpp_get_current_url() { - - // Get URL protocol - $protocol = ( ! isset( $_SERVER[ 'HTTPS' ] ) || $_SERVER[ 'HTTPS' ] !== 'on' ) ? 'http' : 'https'; - - return $protocol . '://' . $_SERVER[ 'HTTP_HOST' ] . $_SERVER[ 'REQUEST_URI' ]; - -} \ No newline at end of file diff --git a/includes/classes/.htaccess b/includes/classes/.htaccess deleted file mode 100644 index 14249c5..0000000 --- a/includes/classes/.htaccess +++ /dev/null @@ -1 +0,0 @@ -Deny from all \ No newline at end of file diff --git a/includes/classes/api.php b/includes/classes/api.php deleted file mode 100644 index 862cfcb..0000000 --- a/includes/classes/api.php +++ /dev/null @@ -1,223 +0,0 @@ -timeout ); - - $url = $this->getUrl( $url ); - $method = strtoupper( $method ); - - // Get headers - $headers = wp_parse_args( - $this->headers, - [ - 'Content-Type' => 'application/json' - ] - ); - - // Check for additional headers - if ( isset( $options[ 'headers' ] ) && is_array( $options[ 'headers' ] ) ) { - - $headers = array_merge( $headers, $options[ 'headers' ] ); - - // Remove headers from options - unset( $options[ 'headers' ] ); - - } - - - // Set args - $args = [ - 'timeout' => $this->timeout, - 'method' => $method, - 'sslverify' => $this->sslverify, - 'body' => $options, - 'headers' => $headers - ]; - - - if ( $cache ) { - // Generate unique cache key for every request - $key = md5( $url . $method . serialize( $options) ); - - if ( $data = $this->getCache( $key ) ) { - return $data; - } - - } - - // Make request - $request = wp_remote_request( $url, $args ); - - $response = [ - 'code' => wp_remote_retrieve_response_code( $request ), - 'message' => wp_remote_retrieve_response_message( $request ), - 'body' => wp_remote_retrieve_body( $request ), - 'cache_key' => '' - ]; - - - // Check for error - if ( is_wp_error( $request ) || ! $this->checkStatusCode( $response ) ) { - - wpp_log( sprintf( 'API request error: %s %s %s', strtoupper( $method ), $url, $response[ 'message' ] ) ); - - return new WP_Error( $response[ 'code' ], $response[ 'message' ], $response ); - - } - - // Cache result ? - if ( $cache ) { - $this->setCache( $key, $response, $cache ); - $response['cache_key'] = $key; - } - - return $response; - - } - - - /** - * Make API request with method - * - * @param string $method - * @param array $args - * @return WP_Error|array - * @since 1.0.8 - */ - public function __call( $method, $args ) { - - $method = strtoupper( $method ); - - if ( in_array( $method, $this->methods ) ) { - - $url = isset( $args[0] ) ? $args[0] : '/'; - $options = isset( $args[1] ) ? $args[1] : []; - $cache = isset( $args[2] ) ? $args[2] : 0; - - return $this->request( $url, $method, $options, $cache ); - - } - - // Log error - wpp_log( sprintf( __( 'Call to undefined method %s', 'wpp' ), $method ) ); - - } - - - /** - * Set response cache - * - * Uses transients to store request response - * - * @param string $key - * @param mixed $data - * @param int $cache numbers of seconds - * @return boolean - * @since 1.0.8 - */ - public function setCache( $key, $data, $cache = 300 ) { - return set_transient( wpp_get_prefix( $key ), $data, $cache ); - } - - /** - * Get cached data - * - * @param string $key - * @return array|boolean - * @since 1.0.8 - */ - public function getCache( $key ) { - - $data = get_transient( wpp_get_prefix( $key ) ); - - if ( $data !== false ) { - return $data; - } - - return false; - - } - - /** - * Clear cache - * - * If cache key is not provided, all cache will be deleted - * - * @param string $key - * @return boolean - * @since 1.0.8 - */ - public function clearCache( $key = null ) { - - if ( is_null( $key ) ) { - - return $GLOBALS[ 'wpdb' ]->query( - 'DELETE FROM ' . $GLOBALS[ 'wpdb' ]->prefix . 'options WHERE option_name LIKE ("%transient_' . esc_sql( wpp_get_prefix() ) . '%")' - ); - - } - - return delete_transient( wpp_get_prefix( $key ) ); - } - - - /** - * Get API url - * - * @param string $url - * @return string - * @since 1.0.8 - */ - public function getUrl( $url = '' ) { - - // Check if its custom API url - if ( strstr( $url, 'http://' ) || strstr( $url, 'https://' ) ) { - return $url; - } - - $namespace = ! is_null( $this->namespace ) ? trailingslashit( $this->namespace ) : ''; - return trailingslashit( $this->api_url ) . $namespace . ltrim( $url, '/' ); - } - - - /** - * Check API response status code - * - * @param array $response - * @return boolean - * @since 1.0.8 - */ - public function checkStatusCode( $response ) { - return ( $response['code'] >= 200 && $response['code'] < 300 ) ? true : false; - } - - -} \ No newline at end of file diff --git a/includes/classes/cache.php b/includes/classes/cache.php deleted file mode 100644 index 31d1cff..0000000 --- a/includes/classes/cache.php +++ /dev/null @@ -1,228 +0,0 @@ - -* @package WPP -*/ - -use RecursiveIteratorIterator; -use RecursiveDirectoryIterator; -use DirectoryIterator; - - -class Cache -{ - - /** - * Save cache - * - * @param string $html - * @param bool $amp - * @since 1.0.0 - * @return void - */ - public static function save( $html, $amp = false ) { - - $file = Cache::getFileName(); - - if ( ! file_exists( $file ) ) { - - $cache_dir = dirname( $file ); - - if ( ! is_dir( $cache_dir ) ) - mkdir( $cache_dir, 0755, true ); - - } - - // Check mobile cache - if ( Option::boolval( 'mobile_cache' ) && wp_is_mobile() ) - $file .= '_mobile'; - - // Allow others to use this - $content = apply_filters( 'wpp_save_cache', $html ); - - /** - * Before saving cache hook - * @since 1.0.0 - */ - do_action( 'wpp_before_cache_save', $file, $content ); - - File::save( ( $amp ) ? $file . '_amp' : $file , $content ); - - if ( function_exists( 'gzencode' ) ) { - - $content = gzencode( $content, apply_filters( 'wpp_gzencode_compression_level', 3 ) ); - - File::save( ( $amp ) ? $file . '_amp_gz' : $file . '_gz' , $content ); - - } - - /** - * After saving cache hook - * @since 1.0.0 - */ - do_action( 'wpp_after_cache_save', $file, $content ); - - wpp_log( sprintf( 'Cache saved for URL %s', Url::current() ) ); - - } - - - /** - * Clar cache - * - * @since 1.0.0 - * @param boolean $preload - * @return void - */ - public static function clear( $preload = true ) { - - /** - * Hook fired right before deleting the cache files - * @since 1.0.0 - */ - do_action( 'wpp-before-cache-delete' ); - - $cache_dir = WPP_CACHE_DIR; - - // Do not delte extensions - $keep_extensions = [ 'log', 'json' ]; - - // Keep assets? - if ( Option::boolval( 'clear_assets' ) ) - array_push( $keep_extensions, 'css', 'js' ); - - if ( is_multisite() ) { - - $uri = parse_url( get_bloginfo( 'url' ) ); - - $cache_dir = WPP_CACHE_DIR . $uri[ 'host' ] . $uri[ 'path' ]; - - // Delete minified CSS and JS files in root cache directory - $root_files = new DirectoryIterator( WPP_CACHE_DIR ); - - foreach ( $root_files as $file ) { - - if ( $file->isFile() ) { - - if ( - ! in_array( $file->getExtension(), $keep_extensions ) - && $file->getFilename() != 'index.php' - ) - unlink( $file->getPathname() ); - - } - - } - - } - - if ( ! is_dir( $cache_dir ) ) - return; - - $files = new RecursiveIteratorIterator( - new RecursiveDirectoryIterator( $cache_dir, RecursiveDirectoryIterator::SKIP_DOTS ), - RecursiveIteratorIterator::CHILD_FIRST - ); - - foreach ( $files as $file ) { - - if ( $file->isDir() ) { - - rmdir( $file->getRealPath() ); - - } else { - - if ( - ! in_array( $file->getExtension(), $keep_extensions ) - && $file->getFilename() != 'index.php' - ) - unlink( $file->getPathname() ); - - } - - } - - wpp_log( 'Cache deleted' ); - - /** - * Hook fired right after deleting the cache files - * @since 1.0.0 - */ - do_action( 'wpp-after-cache-delete' ); - - if ( $preload ) wpp_preload_homepage(); - - } - - - /** - * Delete everything in WPP cache directory and after that delete directory itself - * - * @return void - * @since 1.1.1 - */ - public static function clearEverything() { - - $files = new RecursiveIteratorIterator( - new RecursiveDirectoryIterator( WPP_CACHE_DIR, RecursiveDirectoryIterator::SKIP_DOTS ), - RecursiveIteratorIterator::CHILD_FIRST - ); - - foreach ( $files as $file ) { - - if ( $file->isDir() ) { - rmdir( $file->getRealPath() ); - } else { - unlink( $file->getRealPath() ); - } - - } - - // Remove wpp cache dir - rmdir( WPP_CACHE_DIR ); - - } - - - /** - * Check if cache file exists - * - * @param string $url - * @return boolean - * @since 1.0.0 - */ - public static function exists( $url ) { - return file_exists( Cache::getFileName( $url ) ); - } - - - /** - * Get cache file name - * - * @param string|null $url - * @return string - * @since 1.0.0 - */ - static function getFileName( $url = null ) { - - if ( get_option( 'permalink_structure', true ) ) { - - if ( ! empty( $_GET ) ) { - $uri = parse_url( Input::server( 'REQUEST_URI' ) ); - return WPP_CACHE_DIR . Input::server( 'HTTP_HOST' ) . $uri[ 'path' ] . md5( $uri[ 'query' ] ) . '.html'; - } - - return WPP_CACHE_DIR . trailingslashit( Input::server( 'HTTP_HOST' ) . Input::server( 'REQUEST_URI' ) ) . 'index.html'; - - } else { - - $name = is_null( $url ) ? Url::current() : $url; - return WPP_CACHE_DIR . trailingslashit( Input::server( 'HTTP_HOST' ) ) . md5( $name ) . '.html'; - - } - - } - -} \ No newline at end of file diff --git a/includes/classes/cli.php b/includes/classes/cli.php deleted file mode 100644 index 92182d8..0000000 --- a/includes/classes/cli.php +++ /dev/null @@ -1,136 +0,0 @@ - -* @package WPP -*/ - -use WP_CLI; -use WP_CLI_Command; - -class CLI extends WP_CLI_Command -{ - - /** - * Clear cache - * - * @since 1.0.0 - * @return void - */ - public function flush() { - - WP_CLI::line( esc_html__( 'Flushing the cache...', 'wpp' ) ); - Cache::clear( false ); - WP_CLI::line( esc_html__( 'Cache flushed.', 'wpp' ) ); - - } - - /** - * Temporarily disable plugin - * - * @since 1.0.0 - * @return void - */ - public function disable() { - - WP_CLI::line( esc_html__( sprintf( 'Disabling %s...', WPP_PLUGIN_NAME ), 'wpp' ) ); - Option::update( 'wpp_disable', true ); - File::saveSiteSettings( [ 'disable' => true ] ); - WP_CLI::line( esc_html__( sprintf( '%s disabled', WPP_PLUGIN_NAME ), 'wpp' ) ); - - } - - /** - * Enable plugin - * - * @since 1.0.0 - * @return void - */ - public function enable() { - - WP_CLI::line( esc_html__( sprintf( 'Enabling %s...', WPP_PLUGIN_NAME ), 'wpp' ) ); - Option::update( 'wpp_disable', false ); - File::saveSiteSettings( [ 'disable' => false ] ); - WP_CLI::line( esc_html__( sprintf( '%s enabled', WPP_PLUGIN_NAME ), 'wpp' ) ); - - } - - /** - * Cleanup database - * - * @since 1.0.5 - * @return void - */ - public function cleanup( $args ) { - - if ( isset( $args[ 0 ] ) ) { - - switch( $args[ 0 ] ) { - - case 'transients': - - WP_CLI::line( esc_html__( 'Running tranisent cleanup', 'wpp' ) ); - DB::clearTransients(); - WP_CLI::line( esc_html__( 'Transient cleanup complete', 'wpp' ) ); - - break; - - case 'revisions': - - WP_CLI::line( esc_html__( 'Running revisions cleanup', 'wpp' ) ); - DB::clearRevisions(); - WP_CLI::line( esc_html__( 'Revisions cleanup complete', 'wpp' ) ); - - break; - - case 'drafts': - - WP_CLI::line( esc_html__( 'Running drafts cleanup', 'wpp' ) ); - DB::clearDrafts(); - WP_CLI::line( esc_html__( 'Drafts cleanup complete', 'wpp' ) ); - - break; - - case 'trash': - - WP_CLI::line( esc_html__( 'Running trash cleanup', 'wpp' ) ); - DB::clearTrash(); - WP_CLI::line( esc_html__( 'Trash cleanup complete', 'wpp' ) ); - - break; - - case 'spam': - - WP_CLI::line( esc_html__( 'Running spam cleanup', 'wpp' ) ); - DB::clearSpam(); - WP_CLI::line( esc_html__( 'Spam cleanup complete', 'wpp' ) ); - - break; - - case 'cron': - - WP_CLI::line( esc_html__( 'Running cron tasks cleanup', 'wpp' ) ); - DB::clearCronTasks(); - WP_CLI::line( esc_html__( 'Cron tasks cleanup complete', 'wpp' ) ); - - break; - - } - - } else { - - /** - * Clear all - */ - WP_CLI::line( esc_html__( 'Running database cleanup', 'wpp' ) ); - DB::clear(); - WP_CLI::line( esc_html__( 'Database cleanup complete', 'wpp' ) ); - - } - - } - -} - -WP_CLI::add_command( 'wpp', 'WPP\CLI' ); \ No newline at end of file diff --git a/includes/classes/collection.php b/includes/classes/collection.php deleted file mode 100644 index cc718a5..0000000 --- a/includes/classes/collection.php +++ /dev/null @@ -1,94 +0,0 @@ - -* @package WPP -*/ - -class Collection -{ - private static $collection = []; - - /** - * Add data to collection - * - * @since 1.0.0 - * - * @param string $name - * @param string $type - * @param mixed $file - * @param boolean $unique - * - * @return void - */ - public static function add( $name, $type, $file, $unique = false ) { - - static::$collection[ $name ][ $type ][] = $file; - - if ( $unique ) { - static::$collection[ $name ][ $type ] = array_unique( static::$collection[ $name ][ $type ] ); - } - - } - - - /** - * Get collection - * - * @since 1.0.0 - * - * @param string $name - * @param string $type - * @param mixed $fallback default array - * - * @return array - */ - public static function get( $name, $type = null, $fallback = [] ) { - - if ( ! isset( static::$collection[ $name ] ) ) { - return $fallback; - } - - if ( ! is_null( $type ) ) { - - if ( isset( static::$collection[ $name ][ $type ] ) ) { - return static::$collection[ $name ][ $type ]; - } - - return []; - - } - - return static::$collection[ $name ]; - - } - - - /** - * Remove items from collection - * - * @param string $name - * @param string $type - * @return void - * @since 1.0.0 - */ - public static function remove( $name, $type = null ) { - - if ( isset( static::$collection[ $name ] ) ) { - - if ( ! is_null( $type ) ) { - - if ( isset( static::$collection[ $name ][ $type ] ) ) { - unset( static::$collection[ $name ][ $type ] ); - } - - } - - unset( static::$collection[ $name ] ); - - } - - } - -} \ No newline at end of file diff --git a/includes/classes/db.php b/includes/classes/db.php deleted file mode 100644 index 2b1d1f6..0000000 --- a/includes/classes/db.php +++ /dev/null @@ -1,278 +0,0 @@ - -* @package WPP -*/ - -class DB -{ - /** - * Get revisions count - * - * @return integer - * @since 1.0.0 - */ - public static function getRevisionsCount() { - $result = $GLOBALS['wpdb']->get_row(' - SELECT COUNT(ID) as num - FROM ' . $GLOBALS['wpdb']->posts . ' - WHERE post_type = "revision"' - ); - - return empty($result) ? 0 : $result->num; - } - - /** - * Get spam comments count - * - * @return integer - * @since 1.0.0 - */ - public static function getSpamCount() { - $result = $GLOBALS['wpdb']->get_row(' - SELECT COUNT(*) as num - FROM ' . $GLOBALS['wpdb']->comments . ' - WHERE comment_approved = "spam" - OR comment_approved = "trash"' - ); - - return empty($result) ? 0 : $result->num; - } - - /** - * Get items in trash count - * - * @return integer - * @since 1.0.0 - */ - public static function getTrashCount() { - $result = $GLOBALS['wpdb']->get_row(' - SELECT COUNT(ID) as num - FROM ' . $GLOBALS['wpdb']->posts . ' - WHERE post_status = "trash"' - ); - - return empty($result) ? 0 : $result->num; - - } - - /** - * Get transients count - * - * @return integer - * @since 1.0.0 - */ - public static function getTransientsCount() { - - list(, $seconds) = explode(' ', microtime()); - - $result = $GLOBALS['wpdb']->get_row(' - SELECT COUNT(*) as num - FROM ' . $GLOBALS['wpdb']->options . ' - WHERE option_name LIKE "%_transient_timeout_%" - AND option_value < ' . $seconds - ); - - return empty($result) ? 0 : $result->num; - - } - - /** - * Get transients count - * - * @return integer - * @since 1.0.3 - */ - public static function getCronTasksCount() { - - $count = 0; - - $tasks = get_option( 'cron' ); - - if ( is_array( $tasks ) ) { - - foreach( $tasks as $id => $task ) { - - if ( is_array( $task ) ) { - - foreach( $task as $hook => $data ) { - - // Check if hook has action - if ( ! has_action( $hook ) ) { - $count++; - } - } - - } - - } - - } - - - return $count; - - } - - /** - * Get drafts count - * - * @return integer - * @since 1.0.5 - */ - public static function getAutoDraftsCount() { - $result = $GLOBALS[ 'wpdb' ]->get_row(' - SELECT COUNT(ID) as num - FROM ' . $GLOBALS[ 'wpdb' ]->posts . ' - WHERE post_status = "auto-draft"' - ); - - return empty( $result ) ? 0 : $result->num; - } - - /** - * Run all db cleanups - * - * @return void - * @since 1.0.0 - */ - public static function clear() { - DB::clearRevisions(); - DB::clearSpam(); - DB::clearTrash(); - DB::clearTransients(); - DB::clearCronTasks(); - DB::clearAutoDrafts(); - - wpp_log( 'DB optimized' ); - } - - - /** - * Cleanup revisions - * - * @return void - * @since 1.0.0 - */ - public static function clearRevisions() { - - wpp_log( 'DB revisions deleted' ); - - return $GLOBALS['wpdb']->query( - 'DELETE FROM ' . $GLOBALS['wpdb']->posts .' WHERE post_type = "revision"' - ); - } - - - /** - * Cleanup spam - * - * @return void - * @since 1.0.0 - */ - public static function clearSpam() { - - wpp_log( 'DB spam deleted' ); - - return $GLOBALS['wpdb']->query( - 'DELETE FROM ' . $GLOBALS['wpdb']->comments .' WHERE comment_approved = "spam" OR comment_approved = "trash"' - ); - } - - - /** - * Cleanup trash - * - * @return void - * @since 1.0.0 - */ - public static function clearTrash() { - - wpp_log( 'DB trash deleted' ); - - return $GLOBALS['wpdb']->query( - 'DELETE FROM ' . $GLOBALS['wpdb']->posts . ' WHERE post_status = "trash"' - ); - } - - - /** - * Cleanup transients - * - * @return void - * @since 1.0.0 - */ - public static function clearTransients() { - - wpp_log( 'DB transients deleted' ); - - return $GLOBALS['wpdb']->query( - 'DELETE FROM ' . $GLOBALS['wpdb']->options . ' WHERE option_name LIKE "%_transient_%"' - ); - } - - - /** - * Cleanup cron tasks - * - * @return void - * @since 1.0.0 - */ - public static function clearCronTasks() { - - $tasks = get_option( 'cron' ); - - if ( is_array( $tasks ) ) { - - foreach( $tasks as $id => $task ) { - - if ( is_array( $task ) ) { - - foreach( $task as $hook => $data ) { - - // Check if hook has action - if ( ! has_action( $hook ) ) { - - // Remove action - unset( $tasks[ $id ][ $hook ] ); - - // If there is no other actions, remove hook - if ( count( $tasks[ $id ] ) == 0 ) { - unset( $tasks[ $id ] ); - } - - } - } - - } - - } - - } - - update_option( 'cron', $tasks ); - - wpp_log( 'DB cron tasks deleted' ); - - } - - /** - * Cleanup drafts - * - * @return void - * @since 1.0.5 - */ - public static function clearAutoDrafts() { - - - wpp_log( 'DB auto drafts deleted' ); - - return $GLOBALS['wpdb']->query( - 'DELETE FROM ' . $GLOBALS['wpdb']->posts .' WHERE post_status = "auto-draft"' - ); - - } - -} \ No newline at end of file diff --git a/includes/classes/file.php b/includes/classes/file.php deleted file mode 100644 index 5b5091c..0000000 --- a/includes/classes/file.php +++ /dev/null @@ -1,195 +0,0 @@ - -* @package WPP -*/ - -class File -{ - /** - * Get absolute file path from url - * - * @since 1.0.0 - * @param string $file_url - * @return string - */ - public static function path( $file_url ) { - return realpath( ABSPATH . str_replace( site_url(), '', strtok( $file_url, '?#' ) ) ); - } - - /** - * Check if file is local from given url - * - * @since 1.0.0 - * @param string $file_url - * @return boolean - */ - public static function isLocal( $file_url ) { - return is_file( static::path( $file_url ) ); - } - - /** - * Get file contents - * - * @since 1.0.0 - * @param string $file - * - * @return string - */ - public static function get( $file ) { - - if ( file_exists( $file ) ) { - return file_get_contents( $file ); - } - - return false; - - } - - - /** - * Get file contents and decode it to json. - * Providing the file extension (.json) is not mandatory - * - * @since 1.0.0 - * @param string $file - * @param boolean $assoc - * - * @return array - */ - public static function getJson( $file, $assoc = true ) { - - if( ! strstr( $file, '.json' ) ) { - $file .= '.json'; - } - - if ( $content = static::get( $file ) ) { - return json_decode( $content , $assoc ); - } - - return false; - - } - - - - /** - * Save file content as json - * Providing the file extension (.json) is not mandatory - * - * @since 1.0.0 - * @param string $file - * @param array $data - * - * @return void - */ - public static function saveJson( $file, $data ) { - - if( ! strstr( $file, '.json' ) ) { - $file .= '.json'; - } - - return File::save( $file, json_encode( $data ) ); - - } - - - - /** - * Save content to file - * - * @see php.net/manual/en/function.file-put-contents.php - * - * @since 1.0.0 - * @param string $file - * @param mixed $content - * @param int $lock - * - * @return bool - */ - public static function save( $file, $content, $lock = LOCK_EX ) { - - if ( is_null( $lock ) ) { - return file_put_contents( $file, $content ); - } - - return file_put_contents( $file, $content, $lock ); - } - - /** - * Append content to file - * - * @see php.net/manual/en/function.file-put-contents.php - * - * @since 1.0.0 - * @param string $file - * @param mixed $content - * @param int $lock - * - * @return bool - */ - public static function append( $file, $content, $lock = LOCK_EX ) { - - if ( is_null( $lock ) ) { - return file_put_contents( $file, $content, FILE_APPEND ); - } - - return file_put_contents( $file, $content, FILE_APPEND | $lock ); - } - - - /** - * Prepend content to file - * - * @see php.net/manual/en/function.file-put-contents.php - * - * @since 1.0.0 - * @param string $file - * @param mixed $content - * @param int $lock - * - * @return bool - */ - public static function prepend( $file, $content, $lock = LOCK_EX ) { - - $old_content = file_exists( $file ) ? file_get_contents( $file ) : ''; - - if ( is_null( $lock ) ) { - return file_put_contents( $file, $content . $old_content ); - } - - return file_put_contents( $file, $content . $old_content, $lock ); - - } - - - /** - * Save site settings used by advanced-cache.php file - * - * @since 1.1.4 - * @param array $settings - * @return void - */ - public static function saveSiteSettings( array $settings ) { - - $settings_file = WPP_CACHE_DIR . Input::server( 'HTTP_HOST' ) . '.settings.json'; - - $defaults = [ - 'cache' => false, - 'disable' => false, - 'mobile_cache' => false, - 'expire' => 3600, - 'exclude' => [], - 'permalinks' => false - ]; - - - $updated_settings = wp_parse_args( $settings, $defaults ); - - File::saveJson( $settings_file, $updated_settings ); - - } - -} \ No newline at end of file diff --git a/includes/classes/htmldom.php b/includes/classes/htmldom.php deleted file mode 100644 index e8b02c2..0000000 --- a/includes/classes/htmldom.php +++ /dev/null @@ -1,1588 +0,0 @@ -size is the "real" number of bytes the dom was created from. - * but for most purposes, it's a really good estimation. - * Paperg - Added the forceTagsClosed to the dom constructor. Forcing tags closed is great for malformed html, but it CAN lead to parsing errors. - * Allow the user to tell us how much they trust the html. - * Paperg add the text and plaintext to the selectors for the find syntax. plaintext implies text in the innertext of a node. text implies that the tag is a text node. - * This allows for us to find tags based on the text they contain. - * Create find_ancestor_tag to see if a tag is - at any level - inside of another specific tag. - * Paperg: added parse_charset so that we know about the character set of the source document. - * NOTE: If the user's system has a routine called get_last_retrieve_url_contents_content_type availalbe, we will assume it's returning the content-type header from the - * last transfer or curl_exec, and we will parse that and use it in preference to any other method of charset detection. - * - * Found infinite loop in the case of broken html in restore_noise. Rewrote to protect from that. - * PaperG (John Schlick) Added get_display_size for "IMG" tags. - * - * Licensed under The MIT License - * Redistributions of files must retain the above copyright notice. - * - * @author S.C. Chen - * @author John Schlick - * @author Rus Carroll - * @version 1.5 ($Rev: 210 $) - * @package PlaceLocalInclude - * @subpackage simple_html_dom - */ - -/** - * All of the Defines for the classes below. - * @author S.C. Chen - */ - - - -define('HDOM_TYPE_ELEMENT', 1); -define('HDOM_TYPE_COMMENT', 2); -define('HDOM_TYPE_TEXT', 3); -define('HDOM_TYPE_ENDTAG', 4); -define('HDOM_TYPE_ROOT', 5); -define('HDOM_TYPE_UNKNOWN', 6); -define('HDOM_QUOTE_DOUBLE', 0); -define('HDOM_QUOTE_SINGLE', 1); -define('HDOM_QUOTE_NO', 3); -define('HDOM_INFO_BEGIN', 0); -define('HDOM_INFO_END', 1); -define('HDOM_INFO_QUOTE', 2); -define('HDOM_INFO_SPACE', 3); -define('HDOM_INFO_TEXT', 4); -define('HDOM_INFO_INNER', 5); -define('HDOM_INFO_OUTER', 6); -define('HDOM_INFO_ENDSPACE', 7); -define('DEFAULT_TARGET_CHARSET', 'UTF-8'); -define('DEFAULT_BR_TEXT', "\r\n"); -define('DEFAULT_SPAN_TEXT', " "); -define('MAX_FILE_SIZE', 600000); - -function wpp_file_get_html($url, $use_include_path = false, $context = null, $offset = - 1, $maxLen = - 1, $lowercase = true, $forceTagsClosed = true, $target_charset = DEFAULT_TARGET_CHARSET, $stripRN = true, $defaultBRText = DEFAULT_BR_TEXT, $defaultSpanText = DEFAULT_SPAN_TEXT) -{ - $dom = new HtmlDOM(null, $lowercase, $forceTagsClosed, $target_charset, $stripRN, $defaultBRText, $defaultSpanText); - $contents = file_get_contents($url, $use_include_path, $context, $offset); - if (empty($contents) || strlen($contents) > MAX_FILE_SIZE) { - return false; - } - $dom->load($contents, $lowercase, $stripRN); - return $dom; -} - -function wpp_str_get_html($str, $lowercase = true, $forceTagsClosed = true, $target_charset = DEFAULT_TARGET_CHARSET, $stripRN = true, $defaultBRText = DEFAULT_BR_TEXT, $defaultSpanText = DEFAULT_SPAN_TEXT) -{ - $dom = new HtmlDOM(null, $lowercase, $forceTagsClosed, $target_charset, $stripRN, $defaultBRText, $defaultSpanText); - if (empty($str) || strlen($str) > MAX_FILE_SIZE) { - $dom->clear(); - return false; - } - $dom->load($str, $lowercase, $stripRN); - return $dom; -} - -function dump_html_tree($node, $show_attr = true, $deep = 0) -{ - $node->dump($node); -} - -class simple_html_dom_node -{ - public $nodetype = HDOM_TYPE_TEXT; - - public $tag = 'text'; - - public $attr = array(); - public $children = array(); - public $nodes = array(); - public $parent = null; - - public $_ = array(); - public $tag_start = 0; - - private $dom = null; - function __construct($dom) - { - $this->dom = $dom; - $dom->nodes[] = $this; - } - function __destruct() - { - $this->clear(); - } - function __toString() - { - return $this->outertext(); - } - - function clear() - { - $this->dom = null; - $this->nodes = null; - $this->parent = null; - $this->children = null; - } - - function dump($show_attr = true, $deep = 0) - { - $lead = str_repeat(' ', $deep); - echo $lead . $this->tag; - if ($show_attr && count($this->attr) > 0) { - echo '('; - foreach($this->attr as $k => $v) echo "[$k]=>\"" . $this->$k . '", '; - echo ')'; - } - echo "\n"; - if ($this->nodes) { - foreach($this->nodes as $c) { - $c->dump($show_attr, $deep + 1); - } - } - } - - function dump_node($echo = true) - { - $string = $this->tag; - if (count($this->attr) > 0) { - $string.= '('; - foreach($this->attr as $k => $v) { - $string.= "[$k]=>\"" . $this->$k . '", '; - } - $string.= ')'; - } - if (count($this->_) > 0) { - $string.= ' $_ ('; - foreach($this->_ as $k => $v) { - if (is_array($v)) { - $string.= "[$k]=>("; - foreach($v as $k2 => $v2) { - $string.= "[$k2]=>\"" . $v2 . '", '; - } - $string.= ")"; - } - else { - $string.= "[$k]=>\"" . $v . '", '; - } - } - $string.= ")"; - } - if (isset($this->text)) { - $string.= " text: (" . $this->text . ")"; - } - $string.= " HDOM_INNER_INFO: '"; - if (isset($node->_[HDOM_INFO_INNER])) { - $string.= $node->_[HDOM_INFO_INNER] . "'"; - } - else { - $string.= ' NULL '; - } - $string.= " children: " . count($this->children); - $string.= " nodes: " . count($this->nodes); - $string.= " tag_start: " . $this->tag_start; - $string.= "\n"; - if ($echo) { - echo $string; - return; - } - else { - return $string; - } - } - - function parent($parent = null) - { - if ($parent !== null) { - $this->parent = $parent; - $this->parent->nodes[] = $this; - $this->parent->children[] = $this; - } - return $this->parent; - } - - function has_child() - { - return !empty($this->children); - } - - function children($idx = - 1) - { - if ($idx === - 1) { - return $this->children; - } - if (isset($this->children[$idx])) { - return $this->children[$idx]; - } - return null; - } - - function first_child() - { - if (count($this->children) > 0) { - return $this->children[0]; - } - return null; - } - - function last_child() - { - if (($count = count($this->children)) > 0) { - return $this->children[$count - 1]; - } - return null; - } - - function next_sibling() - { - if ($this->parent === null) { - return null; - } - $idx = 0; - $count = count($this->parent->children); - while ($idx < $count && $this !== $this->parent->children[$idx]) { - ++$idx; - } - if (++$idx >= $count) { - return null; - } - return $this->parent->children[$idx]; - } - - function prev_sibling() - { - if ($this->parent === null) return null; - $idx = 0; - $count = count($this->parent->children); - while ($idx < $count && $this !== $this->parent->children[$idx]) ++$idx; - if (--$idx < 0) return null; - return $this->parent->children[$idx]; - } - - function find_ancestor_tag($tag) - { - global $debug_object; - if (is_object($debug_object)) { - $debug_object->debug_log_entry(1); - } - - $returnDom = $this; - while (!is_null($returnDom)) { - if (is_object($debug_object)) { - $debug_object->debug_log(2, "Current tag is: " . $returnDom->tag); - } - if ($returnDom->tag == $tag) { - break; - } - $returnDom = $returnDom->parent; - } - return $returnDom; - } - - function innertext() - { - if (isset($this->_[HDOM_INFO_INNER])) return $this->_[HDOM_INFO_INNER]; - if (isset($this->_[HDOM_INFO_TEXT])) return $this->dom->restore_noise($this->_[HDOM_INFO_TEXT]); - $ret = ''; - foreach($this->nodes as $n) $ret.= $n->outertext(); - return $ret; - } - - function outertext() - { - global $debug_object; - if (is_object($debug_object)) { - $text = ''; - if ($this->tag == 'text') { - if (!empty($this->text)) { - $text = " with text: " . $this->text; - } - } - $debug_object->debug_log(1, 'Innertext of tag: ' . $this->tag . $text); - } - if ($this->tag === 'root') return $this->innertext(); - - if ($this->dom && $this->dom->callback !== null) { - call_user_func_array($this->dom->callback, array( - $this - )); - } - if (isset($this->_[HDOM_INFO_OUTER])) return $this->_[HDOM_INFO_OUTER]; - if (isset($this->_[HDOM_INFO_TEXT])) return $this->dom->restore_noise($this->_[HDOM_INFO_TEXT]); - - if ($this->dom && $this->dom->nodes[$this->_[HDOM_INFO_BEGIN]]) { - $ret = $this->dom->nodes[$this->_[HDOM_INFO_BEGIN]]->makeup(); - } - else { - $ret = ""; - } - - if (isset($this->_[HDOM_INFO_INNER])) { - if ($this->tag != "br") { - $ret.= $this->_[HDOM_INFO_INNER]; - } - } - else { - if ($this->nodes) { - foreach($this->nodes as $n) { - $ret.= $this->convert_text($n->outertext()); - } - } - } - - if (isset($this->_[HDOM_INFO_END]) && $this->_[HDOM_INFO_END] != 0) $ret.= 'tag . '>'; - return $ret; - } - - function text() - { - if (isset($this->_[HDOM_INFO_INNER])) return $this->_[HDOM_INFO_INNER]; - switch ($this->nodetype) { - case HDOM_TYPE_TEXT: - return $this->dom->restore_noise($this->_[HDOM_INFO_TEXT]); - case HDOM_TYPE_COMMENT: - return ''; - case HDOM_TYPE_UNKNOWN: - return ''; - } - if (strcasecmp($this->tag, 'script') === 0) return ''; - if (strcasecmp($this->tag, 'style') === 0) return ''; - $ret = ''; - - if (!is_null($this->nodes)) { - foreach($this->nodes as $n) { - $ret.= $this->convert_text($n->text()); - } - if ($this->tag == "span") { - $ret.= $this->dom->default_span_text; - } - } - return $ret; - } - function xmltext() - { - $ret = $this->innertext(); - $ret = str_ireplace('', '', $ret); - return $ret; - } - - function makeup() - { - if (isset($this->_[HDOM_INFO_TEXT])) return $this->dom->restore_noise($this->_[HDOM_INFO_TEXT]); - $ret = '<' . $this->tag; - $i = - 1; - foreach($this->attr as $key => $val) { - ++$i; - if ($val === null || $val === false) continue; - $ret.= $this->_[HDOM_INFO_SPACE][$i][0]; - if ($val === true) $ret.= $key; - else { - switch ($this->_[HDOM_INFO_QUOTE][$i]) { - case HDOM_QUOTE_DOUBLE: - $quote = '"'; - break; - - case HDOM_QUOTE_SINGLE: - $quote = '\''; - break; - - default: - $quote = ''; - } - $ret.= $key . $this->_[HDOM_INFO_SPACE][$i][1] . '=' . $this->_[HDOM_INFO_SPACE][$i][2] . $quote . $val . $quote; - } - } - $ret = $this->dom->restore_noise($ret); - return $ret . $this->_[HDOM_INFO_ENDSPACE] . '>'; - } - - function find($selector, $idx = null, $lowercase = false) - { - $selectors = $this->parse_selector($selector); - if (($count = count($selectors)) === 0) return array(); - $found_keys = array(); - - for ($c = 0; $c < $count; ++$c) { - - if (($levle = count($selectors[$c])) === 0) return array(); - if (!isset($this->_[HDOM_INFO_BEGIN])) return array(); - $head = array( - $this->_[HDOM_INFO_BEGIN] => 1 - ); - - for ($l = 0; $l < $levle; ++$l) { - $ret = array(); - foreach($head as $k => $v) { - $n = ($k === - 1) ? $this->dom->root : $this->dom->nodes[$k]; - $n->seek($selectors[$c][$l], $ret, $lowercase); - } - $head = $ret; - } - foreach($head as $k => $v) { - if (!isset($found_keys[$k])) { - $found_keys[$k] = 1; - } - } - } - - ksort($found_keys); - $found = array(); - foreach($found_keys as $k => $v) $found[] = $this->dom->nodes[$k]; - - if (is_null($idx)) return $found; - else if ($idx < 0) $idx = count($found) + $idx; - return (isset($found[$idx])) ? $found[$idx] : null; - } - - protected function seek($selector, &$ret, $lowercase = false) - { - global $debug_object; - if (is_object($debug_object)) { - $debug_object->debug_log_entry(1); - } - list($tag, $key, $val, $exp, $no_key) = $selector; - - if ($tag && $key && is_numeric($key)) { - $count = 0; - foreach($this->children as $c) { - if ($tag === '*' || $tag === $c->tag) { - if (++$count == $key) { - $ret[$c->_[HDOM_INFO_BEGIN]] = 1; - return; - } - } - } - return; - } - $end = (!empty($this->_[HDOM_INFO_END])) ? $this->_[HDOM_INFO_END] : 0; - if ($end == 0) { - $parent = $this->parent; - while (!isset($parent->_[HDOM_INFO_END]) && $parent !== null) { - $end-= 1; - $parent = $parent->parent; - } - $end+= $parent->_[HDOM_INFO_END]; - } - for ($i = $this->_[HDOM_INFO_BEGIN] + 1; $i < $end; ++$i) { - $node = $this->dom->nodes[$i]; - $pass = true; - if ($tag === '*' && !$key) { - if (in_array($node, $this->children, true)) $ret[$i] = 1; - continue; - } - - if ($tag && $tag != $node->tag && $tag !== '*') { - $pass = false; - } - - if ($pass && $key) { - if ($no_key) { - if (isset($node->attr[$key])) $pass = false; - } - else { - if (($key != "plaintext") && !isset($node->attr[$key])) $pass = false; - } - } - - if ($pass && $key && $val && $val !== '*') { - - if ($key == "plaintext") { - $nodeKeyValue = $node->text(); - } - else { - $nodeKeyValue = $node->attr[$key]; - } - if (is_object($debug_object)) { - $debug_object->debug_log(2, "testing node: " . $node->tag . " for attribute: " . $key . $exp . $val . " where nodes value is: " . $nodeKeyValue); - } - - if ($lowercase) { - $check = $this->match($exp, strtolower($val) , strtolower($nodeKeyValue)); - } - else { - $check = $this->match($exp, $val, $nodeKeyValue); - } - if (is_object($debug_object)) { - $debug_object->debug_log(2, "after match: " . ($check ? "true" : "false")); - } - - if (!$check && strcasecmp($key, 'class') === 0) { - foreach(explode(' ', $node->attr[$key]) as $k) { - if (!empty($k)) { - if ($lowercase) { - $check = $this->match($exp, strtolower($val) , strtolower($k)); - } - else { - $check = $this->match($exp, $val, $k); - } - if ($check) break; - } - } - } - if (!$check) $pass = false; - } - if ($pass) $ret[$i] = 1; - unset($node); - } - - if (is_object($debug_object)) { - $debug_object->debug_log(1, "EXIT - ret: ", $ret); - } - } - protected function match($exp, $pattern, $value) - { - global $debug_object; - if (is_object($debug_object)) { - $debug_object->debug_log_entry(1); - } - switch ($exp) { - case '=': - return ($value === $pattern); - case '!=': - return ($value !== $pattern); - case '^=': - return preg_match("/^" . preg_quote($pattern, '/') . "/", $value); - case '$=': - return preg_match("/" . preg_quote($pattern, '/') . "$/", $value); - case '*=': - if ($pattern[0] == '/') { - return preg_match($pattern, $value); - } - return preg_match("/" . $pattern . "/i", $value); - } - return false; - } - protected function parse_selector($selector_string) - { - global $debug_object; - if (is_object($debug_object)) { - $debug_object->debug_log_entry(1); - } - - #$pattern = "/([\w-:\*]*)(?:\#([\w-]+)|\.([\w-]+))?(?:\[@?(!?[\w-:]+)(?:([!*^$]?=)[\"']?(.*?)[\"']?)?\])?([\/, ]+)/is"; - $pattern = "/([\w\-:\*]*)(?:\#([\w\-]+)|\.([\w\-]+))?(?:\[@?(!?[\w\-:]+)(?:([!*^$]?=)[\"']?(.*?)[\"']?)?\])?([\/, ]+)/is"; - preg_match_all($pattern, trim($selector_string) . ' ', $matches, PREG_SET_ORDER); - if (is_object($debug_object)) { - $debug_object->debug_log(2, "Matches Array: ", $matches); - } - $selectors = array(); - $result = array(); - - foreach($matches as $m) { - $m[0] = trim($m[0]); - if ($m[0] === '' || $m[0] === '/' || $m[0] === '//') continue; - if ($m[1] === 'tbody') continue; - list($tag, $key, $val, $exp, $no_key) = array( - $m[1], - null, - null, - '=', - false - ); - if (!empty($m[2])) { - $key = 'id'; - $val = $m[2]; - } - if (!empty($m[3])) { - $key = 'class'; - $val = $m[3]; - } - if (!empty($m[4])) { - $key = $m[4]; - } - if (!empty($m[5])) { - $exp = $m[5]; - } - if (!empty($m[6])) { - $val = $m[6]; - } - - if ($this->dom->lowercase) { - $tag = strtolower($tag); - $key = strtolower($key); - } - - if (isset($key[0]) && $key[0] === '!') { - $key = substr($key, 1); - $no_key = true; - } - $result[] = array( - $tag, - $key, - $val, - $exp, - $no_key - ); - if (trim($m[7]) === ',') { - $selectors[] = $result; - $result = array(); - } - } - if (count($result) > 0) $selectors[] = $result; - return $selectors; - } - function __get($name) - { - if (isset($this->attr[$name])) { - return $this->convert_text($this->attr[$name]); - } - switch ($name) { - case 'outertext': - return $this->outertext(); - case 'innertext': - return $this->innertext(); - case 'plaintext': - return $this->text(); - case 'xmltext': - return $this->xmltext(); - default: - return array_key_exists($name, $this->attr); - } - } - function __set($name, $value) - { - global $debug_object; - if (is_object($debug_object)) { - $debug_object->debug_log_entry(1); - } - switch ($name) { - case 'outertext': - return $this->_[HDOM_INFO_OUTER] = $value; - case 'innertext': - if (isset($this->_[HDOM_INFO_TEXT])) return $this->_[HDOM_INFO_TEXT] = $value; - return $this->_[HDOM_INFO_INNER] = $value; - } - if (!isset($this->attr[$name])) { - $this->_[HDOM_INFO_SPACE][] = array( - ' ', - '', - '' - ); - $this->_[HDOM_INFO_QUOTE][] = HDOM_QUOTE_DOUBLE; - } - $this->attr[$name] = $value; - } - function __isset($name) - { - switch ($name) { - case 'outertext': - return true; - case 'innertext': - return true; - case 'plaintext': - return true; - } - - return (array_key_exists($name, $this->attr)) ? true : isset($this->attr[$name]); - } - function __unset($name) - { - if (isset($this->attr[$name])) unset($this->attr[$name]); - } - - function convert_text($text) - { - global $debug_object; - if (is_object($debug_object)) { - $debug_object->debug_log_entry(1); - } - $converted_text = $text; - $sourceCharset = ""; - $targetCharset = ""; - if ($this->dom) { - $sourceCharset = strtoupper($this->dom->_charset); - $targetCharset = strtoupper($this->dom->_target_charset); - } - if (is_object($debug_object)) { - $debug_object->debug_log(3, "source charset: " . $sourceCharset . " target charaset: " . $targetCharset); - } - if (!empty($sourceCharset) && !empty($targetCharset) && (strcasecmp($sourceCharset, $targetCharset) != 0)) { - if ((strcasecmp($targetCharset, 'UTF-8') == 0) && ($this->is_utf8($text))) { - $converted_text = $text; - } - else { - $converted_text = iconv($sourceCharset, $targetCharset, $text); - } - } - - if ($targetCharset == 'UTF-8') { - if (substr($converted_text, 0, 3) == "\xef\xbb\xbf") { - $converted_text = substr($converted_text, 3); - } - if (substr($converted_text, -3) == "\xef\xbb\xbf") { - $converted_text = substr($converted_text, 0, -3); - } - } - return $converted_text; - } - - static function is_utf8($str) - { - $c = 0; - $b = 0; - $bits = 0; - $len = strlen($str); - for ($i = 0; $i < $len; $i++) { - $c = ord($str[$i]); - if ($c > 128) { - if (($c >= 254)) return false; - elseif ($c >= 252) $bits = 6; - elseif ($c >= 248) $bits = 5; - elseif ($c >= 240) $bits = 4; - elseif ($c >= 224) $bits = 3; - elseif ($c >= 192) $bits = 2; - else return false; - if (($i + $bits) > $len) return false; - while ($bits > 1) { - $i++; - $b = ord($str[$i]); - if ($b < 128 || $b > 191) return false; - $bits--; - } - } - } - return true; - } - - function get_display_size() - { - global $debug_object; - $width = - 1; - $height = - 1; - if ($this->tag !== 'img') { - return false; - } - - if (isset($this->attr['width'])) { - $width = $this->attr['width']; - } - if (isset($this->attr['height'])) { - $height = $this->attr['height']; - } - - if (isset($this->attr['style'])) { - - $attributes = array(); - preg_match_all("/([\w\-]+)\s*:\s*([^;]+)\s*;?/", $this->attr['style'], $matches, PREG_SET_ORDER); - foreach($matches as $match) { - $attributes[$match[1]] = $match[2]; - } - - if (isset($attributes['width']) && $width == - 1) { - - if (strtolower(substr($attributes['width'], -2)) == 'px') { - $proposed_width = substr($attributes['width'], 0, -2); - if (filter_var($proposed_width, FILTER_VALIDATE_INT)) { - $width = $proposed_width; - } - } - } - - if (isset($attributes['height']) && $height == - 1) { - if (strtolower(substr($attributes['height'], -2)) == 'px') { - $proposed_height = substr($attributes['height'], 0, -2); - if (filter_var($proposed_height, FILTER_VALIDATE_INT)) { - $height = $proposed_height; - } - } - } - } - - $result = array( - 'height' => $height, - 'width' => $width - ); - return $result; - } - - function getAllAttributes() - { - return $this->attr; - } - function getAttribute($name) - { - return $this->__get($name); - } - function setAttribute($name, $value) - { - $this->__set($name, $value); - } - function hasAttribute($name) - { - return $this->__isset($name); - } - function removeAttribute($name) - { - $this->__set($name, null); - } - function getElementById($id) - { - return $this->find("#$id", 0); - } - function getElementsById($id, $idx = null) - { - return $this->find("#$id", $idx); - } - function getElementByTagName($name) - { - return $this->find($name, 0); - } - function getElementsByTagName($name, $idx = null) - { - return $this->find($name, $idx); - } - function parentNode() - { - return $this->parent(); - } - function childNodes($idx = - 1) - { - return $this->children($idx); - } - function firstChild() - { - return $this->first_child(); - } - function lastChild() - { - return $this->last_child(); - } - function nextSibling() - { - return $this->next_sibling(); - } - function previousSibling() - { - return $this->prev_sibling(); - } - function hasChildNodes() - { - return $this->has_child(); - } - function nodeName() - { - return $this->tag; - } - function appendChild($node) - { - $node->parent($this); - return $node; - } -} - -class HtmlDOM -{ - public $root = null; - public $nodes = array(); - public $callback = null; - public $lowercase = false; - - public $original_size; - - public $size; - - protected $pos; - protected $doc; - protected $char; - protected $cursor; - protected $parent; - protected $noise = array(); - protected $token_blank = " \t\r\n"; - protected $token_equal = ' =/>'; - protected $token_slash = " />\r\n\t"; - protected $token_attr = ' >'; - public $_charset = ''; - - public $_target_charset = ''; - - protected $default_br_text = ""; - public $default_span_text = ""; - - protected $self_closing_tags = array( - 'img' => 1, - 'br' => 1, - 'input' => 1, - 'meta' => 1, - 'link' => 1, - 'hr' => 1, - 'base' => 1, - 'embed' => 1, - 'spacer' => 1 - ); - protected $block_tags = array( - 'root' => 1, - 'body' => 1, - 'form' => 1, - 'div' => 1, - 'span' => 1, - 'table' => 1 - ); - - protected $optional_closing_tags = array( - 'tr' => array( - 'tr' => 1, - 'td' => 1, - 'th' => 1 - ) , - 'th' => array( - 'th' => 1 - ) , - 'td' => array( - 'td' => 1 - ) , - 'li' => array( - 'li' => 1 - ) , - 'dt' => array( - 'dt' => 1, - 'dd' => 1 - ) , - 'dd' => array( - 'dd' => 1, - 'dt' => 1 - ) , - 'dl' => array( - 'dd' => 1, - 'dt' => 1 - ) , - 'p' => array( - 'p' => 1 - ) , - 'nobr' => array( - 'nobr' => 1 - ) , - 'b' => array( - 'b' => 1 - ) , - 'option' => array( - 'option' => 1 - ) , - ); - function __construct($str = null, $lowercase = true, $forceTagsClosed = true, $target_charset = DEFAULT_TARGET_CHARSET, $stripRN = false, $defaultBRText = DEFAULT_BR_TEXT, $defaultSpanText = DEFAULT_SPAN_TEXT) - { - if ($str) { - $this->load($str, $lowercase, $stripRN, $defaultBRText, $defaultSpanText); - } - - if (!$forceTagsClosed) { - $this->optional_closing_array = array(); - } - $this->_target_charset = $target_charset; - } - function __destruct() - { - $this->clear(); - } - - function load($str, $lowercase = true, $stripRN = true, $defaultBRText = DEFAULT_BR_TEXT, $defaultSpanText = DEFAULT_SPAN_TEXT) - { - global $debug_object; - $this->prepare($str, $lowercase, $stripRN, $defaultBRText, $defaultSpanText); - $this->remove_noise("''is", true); - $this->remove_noise("''is"); - $this->remove_noise("'<\s*script[^>]*[^/]>(.*?)<\s*/\s*script\s*>'is"); - $this->remove_noise("'<\s*script\s*>(.*?)<\s*/\s*script\s*>'is"); - $this->remove_noise("'<\s*style[^>]*[^/]>(.*?)<\s*/\s*style\s*>'is"); - $this->remove_noise("'<\s*style\s*>(.*?)<\s*/\s*style\s*>'is"); - $this->remove_noise("'<\s*(?:code)[^>]*>(.*?)<\s*/\s*(?:code)\s*>'is"); - $this->remove_noise("'(<\?)(.*?)(\?>)'s", true); - $this->remove_noise("'(\{\w)(.*?)(\})'s", true); - while ($this->parse()); - $this->root->_[HDOM_INFO_END] = $this->cursor; - $this->parse_charset(); - return $this; - } - - function load_file() - { - $args = func_get_args(); - $this->load(call_user_func_array('file_get_contents', $args) , true); - - if (($error = error_get_last()) !== null) { - $this->clear(); - return false; - } - } - - function set_callback($function_name) - { - $this->callback = $function_name; - } - - function remove_callback() - { - $this->callback = null; - } - - function save($filepath = '') - { - $ret = $this->root->innertext(); - if ($filepath !== '') file_put_contents($filepath, $ret, LOCK_EX); - return $ret; - } - - function find($selector, $idx = null, $lowercase = false) - { - return $this->root->find($selector, $idx, $lowercase); - } - - function clear() - { - foreach($this->nodes as $n) { - $n->clear(); - $n = null; - } - - if (isset($this->children)) foreach($this->children as $n) { - $n->clear(); - $n = null; - } - if (isset($this->parent)) { - $this->parent->clear(); - unset($this->parent); - } - if (isset($this->root)) { - $this->root->clear(); - unset($this->root); - } - unset($this->doc); - unset($this->noise); - } - function dump($show_attr = true) - { - $this->root->dump($show_attr); - } - - protected function prepare($str, $lowercase = true, $stripRN = true, $defaultBRText = DEFAULT_BR_TEXT, $defaultSpanText = DEFAULT_SPAN_TEXT) - { - $this->clear(); - $this->size = strlen($str); - $this->original_size = $this->size; - if ($stripRN) { - $str = str_replace("\r", " ", $str); - $str = str_replace("\n", " ", $str); - $this->size = strlen($str); - } - $this->doc = $str; - $this->pos = 0; - $this->cursor = 1; - $this->noise = array(); - $this->nodes = array(); - $this->lowercase = $lowercase; - $this->default_br_text = $defaultBRText; - $this->default_span_text = $defaultSpanText; - $this->root = new simple_html_dom_node($this); - $this->root->tag = 'root'; - $this->root->_[HDOM_INFO_BEGIN] = - 1; - $this->root->nodetype = HDOM_TYPE_ROOT; - $this->parent = $this->root; - if ($this->size > 0) $this->char = $this->doc[0]; - } - - protected function parse() - { - if (($s = $this->copy_until_char('<')) === '') { - return $this->read_tag(); - } - - $node = new simple_html_dom_node($this); - ++$this->cursor; - $node->_[HDOM_INFO_TEXT] = $s; - $this->link_nodes($node, false); - return true; - } - - protected function parse_charset() - { - global $debug_object; - $charset = null; - if (function_exists('get_last_retrieve_url_contents_content_type')) { - $contentTypeHeader = get_last_retrieve_url_contents_content_type(); - $success = preg_match('/charset=(.+)/', $contentTypeHeader, $matches); - if ($success) { - $charset = $matches[1]; - if (is_object($debug_object)) { - $debug_object->debug_log(2, 'header content-type found charset of: ' . $charset); - } - } - } - if (empty($charset)) { - $el = $this->root->find('meta[http-equiv=Content-Type]', 0, true); - if (!empty($el)) { - $fullvalue = $el->content; - if (is_object($debug_object)) { - $debug_object->debug_log(2, 'meta content-type tag found' . $fullvalue); - } - if (!empty($fullvalue)) { - $success = preg_match('/charset=(.+)/i', $fullvalue, $matches); - if ($success) { - $charset = $matches[1]; - } - else { - if (is_object($debug_object)) { - $debug_object->debug_log(2, 'meta content-type tag couldn\'t be parsed. using iso-8859 default.'); - } - $charset = 'ISO-8859-1'; - } - } - } - } - - if (empty($charset)) { - $charset = false; - if (function_exists('mb_detect_encoding')) { - $charset = mb_detect_encoding($this->root->plaintext . "ascii", $encoding_list = array( - "UTF-8", - "CP1252" - )); - if (is_object($debug_object)) { - $debug_object->debug_log(2, 'mb_detect found: ' . $charset); - } - } - - if ($charset === false) { - if (is_object($debug_object)) { - $debug_object->debug_log(2, 'since mb_detect failed - using default of utf-8'); - } - $charset = 'UTF-8'; - } - } - - if ((strtolower($charset) == strtolower('ISO-8859-1')) || (strtolower($charset) == strtolower('Latin1')) || (strtolower($charset) == strtolower('Latin-1'))) { - if (is_object($debug_object)) { - $debug_object->debug_log(2, 'replacing ' . $charset . ' with CP1252 as its a superset'); - } - $charset = 'CP1252'; - } - if (is_object($debug_object)) { - $debug_object->debug_log(1, 'EXIT - ' . $charset); - } - return $this->_charset = $charset; - } - - protected function read_tag() - { - if ($this->char !== '<') { - $this->root->_[HDOM_INFO_END] = $this->cursor; - return false; - } - $begin_tag_pos = $this->pos; - $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; - - if ($this->char === '/') { - $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; - - $this->skip($this->token_blank); - $tag = $this->copy_until_char('>'); - - if (($pos = strpos($tag, ' ')) !== false) $tag = substr($tag, 0, $pos); - $parent_lower = strtolower($this->parent->tag); - $tag_lower = strtolower($tag); - if ($parent_lower !== $tag_lower) { - if (isset($this->optional_closing_tags[$parent_lower]) && isset($this->block_tags[$tag_lower])) { - $this->parent->_[HDOM_INFO_END] = 0; - $org_parent = $this->parent; - while (($this->parent->parent) && strtolower($this->parent->tag) !== $tag_lower) $this->parent = $this->parent->parent; - if (strtolower($this->parent->tag) !== $tag_lower) { - $this->parent = $org_parent; - if ($this->parent->parent) $this->parent = $this->parent->parent; - $this->parent->_[HDOM_INFO_END] = $this->cursor; - return $this->as_text_node($tag); - } - } - else if (($this->parent->parent) && isset($this->block_tags[$tag_lower])) { - $this->parent->_[HDOM_INFO_END] = 0; - $org_parent = $this->parent; - while (($this->parent->parent) && strtolower($this->parent->tag) !== $tag_lower) $this->parent = $this->parent->parent; - if (strtolower($this->parent->tag) !== $tag_lower) { - $this->parent = $org_parent; - $this->parent->_[HDOM_INFO_END] = $this->cursor; - return $this->as_text_node($tag); - } - } - else if (($this->parent->parent) && strtolower($this->parent->parent->tag) === $tag_lower) { - $this->parent->_[HDOM_INFO_END] = 0; - $this->parent = $this->parent->parent; - } - else return $this->as_text_node($tag); - } - $this->parent->_[HDOM_INFO_END] = $this->cursor; - if ($this->parent->parent) $this->parent = $this->parent->parent; - $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; - return true; - } - $node = new simple_html_dom_node($this); - $node->_[HDOM_INFO_BEGIN] = $this->cursor; - ++$this->cursor; - $tag = $this->copy_until($this->token_slash); - $node->tag_start = $begin_tag_pos; - - if (isset($tag[0]) && $tag[0] === '!') { - $node->_[HDOM_INFO_TEXT] = '<' . $tag . $this->copy_until_char('>'); - if (isset($tag[2]) && $tag[1] === '-' && $tag[2] === '-') { - $node->nodetype = HDOM_TYPE_COMMENT; - $node->tag = 'comment'; - } - else { - $node->nodetype = HDOM_TYPE_UNKNOWN; - $node->tag = 'unknown'; - } - if ($this->char === '>') $node->_[HDOM_INFO_TEXT].= '>'; - $this->link_nodes($node, true); - $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; - return true; - } - - if ($pos = strpos($tag, '<') !== false) { - $tag = '<' . substr($tag, 0, -1); - $node->_[HDOM_INFO_TEXT] = $tag; - $this->link_nodes($node, false); - $this->char = $this->doc[--$this->pos]; - return true; - } - if (!preg_match("/^[\w\-:]+$/", $tag)) { - $node->_[HDOM_INFO_TEXT] = '<' . $tag . $this->copy_until('<>'); - if ($this->char === '<') { - $this->link_nodes($node, false); - return true; - } - if ($this->char === '>') $node->_[HDOM_INFO_TEXT].= '>'; - $this->link_nodes($node, false); - $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; - return true; - } - - $node->nodetype = HDOM_TYPE_ELEMENT; - $tag_lower = strtolower($tag); - $node->tag = ($this->lowercase) ? $tag_lower : $tag; - - if (isset($this->optional_closing_tags[$tag_lower])) { - while (isset($this->optional_closing_tags[$tag_lower][strtolower($this->parent->tag) ])) { - $this->parent->_[HDOM_INFO_END] = 0; - $this->parent = $this->parent->parent; - } - $node->parent = $this->parent; - } - $guard = 0; - $space = array( - $this->copy_skip($this->token_blank) , - '', - '' - ); - - do { - if ($this->char !== null && $space[0] === '') { - break; - } - $name = $this->copy_until($this->token_equal); - if ($guard === $this->pos) { - $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; - continue; - } - $guard = $this->pos; - - if ($this->pos >= $this->size - 1 && $this->char !== '>') { - $node->nodetype = HDOM_TYPE_TEXT; - $node->_[HDOM_INFO_END] = 0; - $node->_[HDOM_INFO_TEXT] = '<' . $tag . $space[0] . $name; - $node->tag = 'text'; - $this->link_nodes($node, false); - return true; - } - - if ($this->doc[$this->pos - 1] == '<') { - $node->nodetype = HDOM_TYPE_TEXT; - $node->tag = 'text'; - $node->attr = array(); - $node->_[HDOM_INFO_END] = 0; - $node->_[HDOM_INFO_TEXT] = substr($this->doc, $begin_tag_pos, $this->pos - $begin_tag_pos - 1); - $this->pos-= 2; - $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; - $this->link_nodes($node, false); - return true; - } - if ($name !== '/' && $name !== '') { - $space[1] = $this->copy_skip($this->token_blank); - $name = $this->restore_noise($name); - if ($this->lowercase) $name = strtolower($name); - if ($this->char === '=') { - $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; - $this->parse_attr($node, $name, $space); - } - else { - $node->_[HDOM_INFO_QUOTE][] = HDOM_QUOTE_NO; - $node->attr[$name] = true; - if ($this->char != '>') $this->char = $this->doc[--$this->pos]; - } - $node->_[HDOM_INFO_SPACE][] = $space; - $space = array( - $this->copy_skip($this->token_blank) , - '', - '' - ); - } - else break; - } - while ($this->char !== '>' && $this->char !== '/'); - $this->link_nodes($node, true); - $node->_[HDOM_INFO_ENDSPACE] = $space[0]; - - if ($this->copy_until_char_escape('>') === '/') { - $node->_[HDOM_INFO_ENDSPACE].= '/'; - $node->_[HDOM_INFO_END] = 0; - } - else { - if (!isset($this->self_closing_tags[strtolower($node->tag) ])) $this->parent = $node; - } - $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; - - if ($node->tag == "br") { - $node->_[HDOM_INFO_INNER] = $this->default_br_text; - } - return true; - } - - protected function parse_attr($node, $name, &$space) - { - if (isset($node->attr[$name])) { - return; - } - $space[2] = $this->copy_skip($this->token_blank); - switch ($this->char) { - case '"': - $node->_[HDOM_INFO_QUOTE][] = HDOM_QUOTE_DOUBLE; - $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; - $node->attr[$name] = $this->restore_noise($this->copy_until_char_escape('"')); - $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; - break; - - case '\'': - $node->_[HDOM_INFO_QUOTE][] = HDOM_QUOTE_SINGLE; - $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; - $node->attr[$name] = $this->restore_noise($this->copy_until_char_escape('\'')); - $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; - break; - - default: - $node->_[HDOM_INFO_QUOTE][] = HDOM_QUOTE_NO; - $node->attr[$name] = $this->restore_noise($this->copy_until($this->token_attr)); - } - - $node->attr[$name] = str_replace("\r", "", $node->attr[$name]); - $node->attr[$name] = str_replace("\n", "", $node->attr[$name]); - - if ($name == "class") { - $node->attr[$name] = trim($node->attr[$name]); - } - } - - protected function link_nodes(&$node, $is_child) - { - $node->parent = $this->parent; - $this->parent->nodes[] = $node; - if ($is_child) { - $this->parent->children[] = $node; - } - } - - protected function as_text_node($tag) - { - $node = new simple_html_dom_node($this); - ++$this->cursor; - $node->_[HDOM_INFO_TEXT] = ''; - $this->link_nodes($node, false); - $this->char = (++$this->pos < $this->size) ? $this->doc[$this->pos] : null; - return true; - } - protected function skip($chars) - { - $this->pos+= strspn($this->doc, $chars, $this->pos); - $this->char = ($this->pos < $this->size) ? $this->doc[$this->pos] : null; - } - protected function copy_skip($chars) - { - $pos = $this->pos; - $len = strspn($this->doc, $chars, $pos); - $this->pos+= $len; - $this->char = ($this->pos < $this->size) ? $this->doc[$this->pos] : null; - if ($len === 0) return ''; - return substr($this->doc, $pos, $len); - } - protected function copy_until($chars) - { - $pos = $this->pos; - $len = strcspn($this->doc, $chars, $pos); - $this->pos+= $len; - $this->char = ($this->pos < $this->size) ? $this->doc[$this->pos] : null; - return substr($this->doc, $pos, $len); - } - protected function copy_until_char($char) - { - if ($this->char === null) return ''; - if (($pos = strpos($this->doc, $char, $this->pos)) === false) { - $ret = substr($this->doc, $this->pos, $this->size - $this->pos); - $this->char = null; - $this->pos = $this->size; - return $ret; - } - if ($pos === $this->pos) return ''; - $pos_old = $this->pos; - $this->char = $this->doc[$pos]; - $this->pos = $pos; - return substr($this->doc, $pos_old, $pos - $pos_old); - } - protected function copy_until_char_escape($char) - { - if ($this->char === null) return ''; - $start = $this->pos; - while (1) { - if (($pos = strpos($this->doc, $char, $start)) === false) { - $ret = substr($this->doc, $this->pos, $this->size - $this->pos); - $this->char = null; - $this->pos = $this->size; - return $ret; - } - if ($pos === $this->pos) return ''; - if ($this->doc[$pos - 1] === '\\') { - $start = $pos + 1; - continue; - } - $pos_old = $this->pos; - $this->char = $this->doc[$pos]; - $this->pos = $pos; - return substr($this->doc, $pos_old, $pos - $pos_old); - } - } - - protected function remove_noise($pattern, $remove_tag = false) - { - global $debug_object; - if (is_object($debug_object)) { - $debug_object->debug_log_entry(1); - } - $count = preg_match_all($pattern, $this->doc, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE); - for ($i = $count - 1; $i > - 1; --$i) { - $key = '___noise___' . sprintf('% 5d', count($this->noise) + 1000); - if (is_object($debug_object)) { - $debug_object->debug_log(2, 'key is: ' . $key); - } - $idx = ($remove_tag) ? 0 : 1; - $this->noise[$key] = $matches[$i][$idx][0]; - $this->doc = substr_replace($this->doc, $key, $matches[$i][$idx][1], strlen($matches[$i][$idx][0])); - } - - $this->size = strlen($this->doc); - if ($this->size > 0) { - $this->char = $this->doc[0]; - } - } - - function restore_noise($text) - { - global $debug_object; - if (is_object($debug_object)) { - $debug_object->debug_log_entry(1); - } - while (($pos = strpos($text, '___noise___')) !== false) { - - if (strlen($text) > $pos + 15) { - $key = '___noise___' . $text[$pos + 11] . $text[$pos + 12] . $text[$pos + 13] . $text[$pos + 14] . $text[$pos + 15]; - if (is_object($debug_object)) { - $debug_object->debug_log(2, 'located key of: ' . $key); - } - if (isset($this->noise[$key])) { - $text = substr($text, 0, $pos) . $this->noise[$key] . substr($text, $pos + 16); - } - else { - $text = substr($text, 0, $pos) . 'UNDEFINED NOISE FOR KEY: ' . $key . substr($text, $pos + 16); - } - } - else { - $text = substr($text, 0, $pos) . 'NO NUMERIC NOISE KEY' . substr($text, $pos + 11); - } - } - return $text; - } - - function search_noise($text) - { - global $debug_object; - if (is_object($debug_object)) { - $debug_object->debug_log_entry(1); - } - foreach($this->noise as $noiseElement) { - if (strpos($noiseElement, $text) !== false) { - return $noiseElement; - } - } - } - function __toString() - { - return $this->root->innertext(); - } - function __get($name) - { - switch ($name) { - case 'outertext': - return $this->root->innertext(); - case 'innertext': - return $this->root->innertext(); - case 'plaintext': - return $this->root->text(); - case 'charset': - return $this->_charset; - case 'target_charset': - return $this->_target_charset; - } - } - - function childNodes($idx = - 1) - { - return $this->root->childNodes($idx); - } - function firstChild() - { - return $this->root->first_child(); - } - function lastChild() - { - return $this->root->last_child(); - } - function createElement($name, $value = null) - { - return @wpp_str_get_html("<$name>$value")->first_child(); - } - function createTextNode($value) - { - return @end(wpp_str_get_html($value)->nodes); - } - function getElementById($id) - { - return $this->find("#$id", 0); - } - function getElementsById($id, $idx = null) - { - return $this->find("#$id", $idx); - } - function getElementByTagName($name) - { - return $this->find($name, 0); - } - function getElementsByTagName($name, $idx = - 1) - { - return $this->find($name, $idx); - } - function loadFile() - { - $args = func_get_args(); - $this->load_file($args); - } -} diff --git a/includes/classes/image.php b/includes/classes/image.php deleted file mode 100644 index d6e2927..0000000 --- a/includes/classes/image.php +++ /dev/null @@ -1,233 +0,0 @@ - -*/ - -use WP_Query; - -class Image -{ - - /** - * Get image sizes - * - * @return array - * @since 1.0.0 - */ - public static function sizes() { - - $sizes = []; - $default = get_intermediate_image_sizes(); - - foreach ( $default as $size ) { - - if ( $width = intval( get_option( $size . '_size_w' ) ) ) { - - $sizes[ $size ] = [ - $width, - intval( get_option( $size . '_size_h' ) ), - boolval( get_option( $size . '_crop' ) ) - ]; - - } - - } - - if ( - isset( $GLOBALS[ '_wp_additional_image_sizes' ] ) - && count( $GLOBALS[ '_wp_additional_image_sizes' ] ) - ) { - - foreach ( $GLOBALS[ '_wp_additional_image_sizes' ] as $name => $size ) { - - if ( isset( $size[ 'width' ] ) ) { - $sizes[ $name ] = [ - $size[ 'width' ], - $size[ 'height' ], - $size[ 'crop' ] - ]; - } - - } - - } - - $removed_sizes = Option::get( 'image_sizes_remove', [] ); - - foreach( $removed_sizes as $name ) { - - if ( array_key_exists( $name, $sizes ) ) { - unset( $sizes[ $name ] ); - } - - } - - asort( $sizes ); - - return $sizes; - - } - - - /** - * Get all images with non regenerated thumbs - * - * @param integer $number - * @return array - * @since 1.0.0 - */ - public static function getNonRegenerated( $number = -1 ) { - - $result = new WP_Query( [ - 'post_type' => 'attachment', - 'post_mime_type' => [ 'image/jpeg', 'image/gif', 'image/png' ], - 'post_status' => 'inherit', - 'posts_per_page' => $number, - 'meta_query' => [ - [ - 'key' => 'wpp_thumb_regenerated', - 'compare' => 'NOT EXISTS' - ] - ] - ] ); - - return $result->posts; - - } - - - /** - * Get all images from media library - * - * @return array - * @since 1.0.0 - */ - public static function getAllImages() { - - $result = new WP_Query( [ - 'post_type' => 'attachment', - 'post_mime_type' => [ 'image/jpeg', 'image/gif', 'image/png' ], - 'post_status' => 'inherit', - 'posts_per_page' => -1, - ] ); - - return $result->posts; - - } - - - /** - * Get all defined image sizes - * - * @return array - * @since 1.0.0 - */ - public static function getAllDefinedSizes() { - return array_merge( static::sizes(), Option::get( 'image_sizes', [] ) ); - } - - - /** - * Return defined image sizes in json format - * - * @param boolean $encode - * @return array|json - * @since 1.0.0 - */ - public static function getAllDefinedSizesJson( $encode = true ) { - - $sizes = static::getAllDefinedSizes(); - - $response = []; - - foreach ( $sizes as $name => $size ) { - $response[] = [ - 'name' => $name, - 'width' => $size[ 0 ], - 'height' => $size[ 1 ], - 'crop' => $size[ 2 ] ? 1 : 0 - ]; - } - - if ( $encode ) { - return json_encode( $response ); - } - - return $response; - - } - - /** - * Get all variations of an image - * - * @param string $src - * @return array - */ - public static function getAllVariations( $src ) { - - // check if image exists - if( ! file_exists( $file = File::path( $src ) ) ) { - return []; - } - - $images = []; - $sizes = static::getAllDefinedSizes(); - $path = pathinfo( $file ); - $existing = glob( $path[ 'dirname' ] . DIRECTORY_SEPARATOR . $path[ 'filename' ] . '*' ); - - foreach( $sizes as $name => $data ) { - - // Woocommerce have some strange numbers for height, hm... - if ( $data[ 1 ] > ( $data[ 0 ] * 3 ) ) { - continue; - } - - $filename = sprintf( - '%s-%sx%s.%s', - $path[ 'dirname' ] . DIRECTORY_SEPARATOR . $path[ 'filename' ], - $data[ 0 ], $data[ 1 ], - $path[ 'extension' ] - ); - - // Get exact image size - if ( file_exists( $filename ) ) { - - $images[ $data[ 0 ] ] = Url::path( $filename ); - - } else { - - $found = false; - - // find image by width attribute - foreach ( $existing as $existing_image ) { - - $pattern = $path[ 'filename' ] . '-' . $data[ 0 ] . '(.*)\.' . $path[ 'extension' ]; - - if ( preg_match( "/$pattern/", $existing_image ) ) { - $images[ $data[ 0 ] ] = Url::path( $existing_image ); - $found = true; - break; - } - - } - - // Image not found - if ( ! $found ) { - // Fallback - $images[ $data[ 0 ] ] = Url::path( $src ); - - } - - } - - } - - ksort( $images ); - - return $images; - - } - -} \ No newline at end of file diff --git a/includes/classes/index.php b/includes/classes/index.php deleted file mode 100644 index e71af0e..0000000 --- a/includes/classes/index.php +++ /dev/null @@ -1 +0,0 @@ - -* @package WPP -* -* @see Filters http://php.net/manual/en/filter.filters.php -*/ - -class Input -{ - /** - * Get filtered input value - * - * @param string $name - * @param array $args - * @return mixed - * @since 1.0.0 - */ - public static function __callStatic( $name, $args ) { - return call_user_func_array( [ 'WPP\Input', 'filter' ], [ $name, $args ] ); - } - - /** - * Filter input value - * - * @param string $name - * @param array $args - * @return mixed - * @since 1.0.0 - */ - private static function filter( $name, $args ) { - - $params = array_pad( $args, 3, null ); - - if ( $name === 'request' ) { - - if ( isset( $_REQUEST[ $params[ 0 ] ] ) ) { - return filter_var( $_REQUEST[ $params[ 0 ] ], Input::getFilter( $params[ 1 ] ), $params[ 2 ] ); - } - - return $params[ 2 ]; - - } - - return filter_input( Input::getMethod( $name ), $params[ 0 ], Input::getFilter( $params[ 1 ] ), $params[ 2 ] ); - - } - - /** - * Get input method - * - * @param string $name - * @return int - * @since 1.0.0 - */ - private static function getMethod( $name ) { - - switch ( $name ) { - case 'get': - return INPUT_GET; - case 'post': - return INPUT_POST; - case 'cookie': - return INPUT_COOKIE; - case 'session': - return INPUT_SESSION; - case 'server': - return INPUT_SERVER; - case 'env': - return INPUT_ENV; - default: - return 'request'; - - - } - } - - - /** - * Get filter - * - * @see http://php.net/manual/en/function.filter-list.php - * - * @param string $name - * @return void - * @since 1.0.0 - */ - private static function getFilter( $name ) { - - if ( in_array( $name, filter_list() ) ) { - return filter_id( $name ); - } - - return FILTER_SANITIZE_STRING; - } - -} \ No newline at end of file diff --git a/includes/classes/instance.php b/includes/classes/instance.php deleted file mode 100644 index 65e910c..0000000 --- a/includes/classes/instance.php +++ /dev/null @@ -1,36 +0,0 @@ - -* @package WPP -*/ - -trait Instance -{ - - /** - * Class instance - * - * @var class - * @since 1.1.0 - */ - private static $instance; - - /** - * Get class instance - * - * @return class - * @since 1.1.0 - */ - public static function instance() { - - if ( is_null( static::$instance ) ) { - static::$instance = new static(); - } - - return static::$instance; - - } - -} \ No newline at end of file diff --git a/includes/classes/minify.php b/includes/classes/minify.php deleted file mode 100644 index 0b9ab8b..0000000 --- a/includes/classes/minify.php +++ /dev/null @@ -1,119 +0,0 @@ - -* @package WPP -*/ - -use MatthiasMullie\Minify as Minifier; - -class Minify { - - /** - * Minify code - * - * @since 1.0.0 - * - * @param string $code - * @param string $context - * - * @return string - */ - public static function code( $code, $context = null ) { - - $minifier = is_null( $context ) - ? new Minifier\JS( $code ) - : new Minifier\CSS( Minify::replacePaths( $code, $context ) ); - - return $minifier->minify(); - - } - - /** - * Get resource from url and minify the code - * Create a new file with minified code. - * Returns the name of the new file. - * - * @since 1.0.0 - * @param string $url - * - * @return string - */ - public static function resource( $url ) { - - if ( is_file( $file = File::path( $url ) ) ) { - - $extension = pathinfo( $file, PATHINFO_EXTENSION ); - $filename = md5( $file ) . '.' . $extension; - - if ( ! file_exists( $cached = WPP_CACHE_DIR . $filename ) ) { - - // Check if extension is php - if ( $extension == 'php' ) { - $code = wp_remote_retrieve_body( wp_remote_get( $file ) ); - } else { - $code = File::get( $file ); - } - - $minified = $extension == 'css' - ? Minify::code( $code, $url ) - : Minify::code( $code ); - - File::save( $cached, $minified ); - - //touch( $cached, time() - 3600 ); - - } - - return WPP_CACHE_URL . $filename; - } - - return $url; - - } - - - /** - * Replace relative paths with absolute paths - * - * @since 1.0.0 - * - * @param string $code - * @param string $context - * - * @return string - */ - public static function replacePaths( $code, $context ) { - - // Process images - preg_match_all( "/url\((\"|\')?(.*?)(\"|\')?\)/i", $code, $matches, PREG_PATTERN_ORDER ); - - foreach( $matches[2] as $i => $match) { - - $url = str_replace( basename( $context ), '', $context ) . $match; - $url = Url::path( File::path( $url ) ); - - if ( ! empty( $url ) ) { - $code = str_replace( $match, $url, $code ); - } - } - - // Process imports - preg_match_all("/@import[ ]*['\"]*(?:url\()*['\"]*([^;'\"\)]*)['\"\)]*/ui", $code, $matches ); - - foreach( $matches[1] as $i => $match) { - - $url = str_replace( basename( $context ), '', $context ) . $match; - $url = Url::path( File::path( $url ) ); - - if ( ! empty( $url ) ) { - $code = str_replace( $match, $url, $code ); - } - } - - return $code; - - } - -} \ No newline at end of file diff --git a/includes/classes/option.php b/includes/classes/option.php deleted file mode 100644 index 4b65eb4..0000000 --- a/includes/classes/option.php +++ /dev/null @@ -1,142 +0,0 @@ - -* @package WPP -*/ - -class Option -{ - - /** - * Add option - * - * @see https://developer.wordpress.org/reference/functions/add_option/ - * - * @since 1.0.0 - * - * @param string $option - * @param mixed $value - * @param string $deprecated - * @param mixed $autoload - * - * @return boolean - */ - public static function add( $option, $value = '', $deprecated = '', $autoload = 'yes' ) { - return add_option( wpp_get_prefix( $option ), $value, $deprecated, $autoload ); - } - - - /** - * Get option - * - * @see https://developer.wordpress.org/reference/functions/get_option/ - * - * @since 1.0.0 - * - * @param string $option - * @param mixed $default - * - * @return mixed - */ - public static function get( $option, $default = false ) { - - $value = get_option( wpp_get_prefix( $option ), $default ); - - return ( ! $value ) ? $default : $value; - - } - - - /** - * Get option boolean value - * - * @since 1.0.0 - * @param string $option - * @param mixed $default - * - * @return boolean - */ - public static function boolval( $option, $default = false ) { - return boolval( Option::get( $option, $default ) ); - } - - /** - * Update option - * - * @see https://developer.wordpress.org/reference/functions/update_option/ - * - * @since 1.0.0 - * - * @param string $option - * @param mixed $value - * @param mixed $autoload - * - * @return boolean - */ - public static function update( $option, $value, $autoload = true ) { - return update_option( wpp_get_prefix( $option ), $value, $autoload ); - } - - - /** - * Remove option - * - * @see https://developer.wordpress.org/reference/functions/delete_option/ - * - * @since 1.0.0 - * @param string $option - * - * @return boolean - */ - public static function remove( $option ) { - return delete_option( wpp_get_prefix( $option ) ); - } - - - /** - * Remove all options - * - * @since 1.1.6 - * @return void - */ - public static function removeAll() { - - $GLOBALS['wpdb']->query( - sprintf( - 'DELETE FROM %s WHERE option_name LIKE "%s%%"', - $GLOBALS['wpdb']->options, - wpp_get_prefix() - ) - ); - - } - - /** - * Get all options - * - * @since 1.1.6 - * @return array - */ - public static function getAll() { - - $options = []; - - $result = $GLOBALS['wpdb']->get_results( - sprintf( - 'SELECT option_name, option_value FROM %s WHERE option_name LIKE "%s%%"', - $GLOBALS['wpdb']->options, - wpp_get_prefix() - ) - ); - - foreach( $result as $option ) - $options[ $option->option_name ] = maybe_unserialize( $option->option_value ); - - return $options; - - } - - -} \ No newline at end of file diff --git a/includes/classes/parser.php b/includes/classes/parser.php deleted file mode 100644 index 2c7e0e6..0000000 --- a/includes/classes/parser.php +++ /dev/null @@ -1,1128 +0,0 @@ - -* @package WPP -*/ - -use voku\helper\HtmlMin; - -class Parser -{ - private static $instance; - private $html; - private $time; - private static $amp = null; - - private function __construct( $template ) { - - if ( ! empty( $template ) ) { - - $this->time = microtime( true ); - - // load template - $this->html = new HtmlDOM( $template, false, false ); - - if ( $this->html ) { - - $this->htmltag = $this->html->find( 'html', 0 ); - $this->body = $this->html->find( 'body', 0 ); - $this->head = $this->html->find( 'head', 0 ); - - // Do not parse amp templates - if ( ! $this->is_amp() ) - $this->parseTemplate(); - - /** - * Parsed template filter - * @since 1.1.8.3 - */ - $template = apply_filters( 'wpp_template', $this->html, $this->is_amp(), $this->time ); - - } - - } - - return $template; - - } - - /** - * Initialize - * - * @param string $template - * @return Parser - */ - public static function init( $template ) { - - if ( is_null( static::$instance ) ) { - static::$instance = new static( $template ); - } - - return static::$instance; - } - - /** - * Parse template - * - * @return string - * @since 1.0.9 - */ - private function parseTemplate() { - - // Check for head and body tag - if ( ! $this->head || ! $this->body ) { - - // // Check if is XML file - // $headers = headers_list(); - - // foreach( $headers as $header ) { - - // if ( strstr( $header, 'text/xml' ) ) { - // return $this->html; - // } - - // } - - // $this->html .= sprintf( - // '', - // WPP_PLUGIN_NAME, - // __( 'error', 'wpp' ), - // __( 'both head and body tag should be present in template file', 'wpp' ) - // ); - - // wpp_log( __( 'both head and body tag should be present in template file', 'wpp' ) ); - - return $this->html; - - } - - // CSS optimization - - /** - * Exclude URL from CSS optimization filter - * @since 1.0.3 - */ - $css_url_exclude = apply_filters( 'wpp_css_url_exclude', Option::get( 'css_url_exclude', [] ) ); - - if ( - ! wpp_is_optimization_disabled_for( 'css' ) - && ! wpp_is_url_excluded( Url::current(), $css_url_exclude ) - ) { - $this->parseCSS(); - } - - // JS optimization - - /** - * Exclude URL from JavaScript optimization filter - * @since 1.0.3 - */ - $js_url_exclude = apply_filters( 'wpp_js_url_exclude', Option::get( 'js_url_exclude', [] ) ); - - if ( - ! wpp_is_optimization_disabled_for( 'js' ) - && ! wpp_is_url_excluded( Url::current(), $js_url_exclude ) - ) { - $this->parseJS(); - } - - // Images optimization - - /** - * Exclude URL from Images optimization filter - * @since 1.0.4 - */ - $image_url_exclude = apply_filters( 'wpp_image_url_exclude', Option::get( 'image_url_exclude', [] ) ); - - if ( ! wpp_is_url_excluded( Url::current(), $image_url_exclude ) ) - $this->parseImages(); - - /** - * Exclude URL from iframe lazyload filter - * @since 1.1.6 - */ - $video_url_exclude = apply_filters( 'wpp_video_url_exclude', Option::get( 'video_url_exclude', [] ) ); - - if ( - ! wpp_is_url_excluded( Url::current(), $video_url_exclude ) - && Option::boolval( 'videos_lazy' ) - ) { - $this->parseIframes(); - } - - // Rebuild the template - $this->buildTemplate(); - - } - - - /** - * Parse CSS - * - * @return void - */ - private function parseCSS() { - - // Add skip attribute to links in noscript - foreach( $this->html->find( 'noscript link[rel=stylesheet]' ) as $link ) { - $link->{'data-skip'} = 'true'; - } - // Minify inline CSS? - if ( Option::boolval( 'css_minify_inline' ) ) { - - foreach ( $this->html->find( 'style' ) as $style ) { - $style->innertext = Minify::code( $style->innertext, Url::current() ); - } - - } - - - // Parse link stylesheets - foreach ( $this->html->find( 'link[rel=stylesheet]' ) as $link ) { - - if ( - $link->{'data-skip'} == 'true' - || strstr( $link->href, WPP_ASSET_URL ) - || strstr( $link->href, WPP_ADDONS_URL ) - || ( is_user_logged_in() && strstr( $link->href, 'wp-includes' ) ) - ) { - continue; - } - - $href = Url::getClean( $link->href ); - - if ( File::isLocal( $href ) ) { - - if ( $link->media !== 'print' ) - Collection::add( 'critical', 'css', $href ); - - // Is this a plugin file ? - if ( strstr( $link->href, plugins_url() ) ) { - Collection::add( 'plugin', 'css', $href ); - } else { - Collection::add( 'theme', 'css', $href ); - } - - // Check if resource is disabled - if ( wpp_is_resource_disabled( 'css', $href ) ) { - $link->outertext = ''; - continue; - } - - } else { - - if ( $link->href && ! strstr( $link->href, site_url() ) ) { - - Collection::add( 'external', 'css', $link->href ); - - // Check if external resource is disabled - if ( wpp_is_resource_disabled( 'css', wpp_get_file_clean_name( $link->href ) ) ) { - - $link->outertext = ''; - continue; - - } else { - - Collection::add( 'prefetch', 'css', wpp_get_file_hostname( $link->href ), true ); - - } - - - // Combine Google fonts - if ( Option::boolval( 'css_combine_fonts' ) ) { - - if ( strstr( $link->href, 'fonts.googleapis.com' ) ) { - - list( , $url ) = explode( 'family=', $link->href ); - - Collection::add( 'combine', 'google_fonts', html_entity_decode( urldecode( $url ) ), true ); - - $link->outertext = ''; - - continue; - - } - - } - - // Google fonts display - if ( Option::get( 'css_font_display' ) !== 'none' ) { - - if ( strstr( $link->href, 'fonts.googleapis.com' ) ) { - - $url = parse_url( htmlspecialchars_decode( $link->href ) ); - - parse_str( $url['query'], $parameters ); - - $parameters['display'] = Option::get( 'css_font_display' ); - - $link->href = '//fonts.googleapis.com/css?'. http_build_query( $parameters ); - - } - - } - - } - - } - - - // Inline CSS - if ( wpp_in_array( array_keys( Option::get( 'css_inline', [] ) ), $href ) ) { - - if ( File::isLocal( $href ) ) { - - $code = File::get( File::path( $href ) ); - - // Minify file - if ( wpp_in_array( array_keys( Option::get( 'css_minify', [] ) ), $href ) ) { - $code = Minify::code( $code, $href ); - } else { - $code = Minify::replacePaths( $code, $href ); - } - - $link->outertext = ''; - - continue; - - } - - } - - - // Combine CSS - if ( Option::boolval( 'css_combine' ) ) { - - if ( File::isLocal( $href ) ) { - - if ( wpp_in_array( array_keys( Option::get( 'css_combine' ) ), $href ) ) { - - if ( Option::boolval( 'css_defer' ) ) { - - // Exclude file from async loading will exclude also exclude file from combine - if ( ! wpp_in_array( Option::get( 'css_file_exclude', [] ), $href ) ) { - - Collection::add( 'combine', 'css', [ - 'href' => $href, - 'media' => !$link->media ? 'all' : $link->media - ] ); - - $link->outertext = ''; - - continue; - - } - - } else { - - Collection::add( 'combine', 'css', [ - 'href' => $href, - 'media' => !$link->media ? 'all' : $link->media - ] ); - - $link->outertext = ''; - - continue; - - } - - } - - } - - } - - // Minify CSS - if ( - Option::boolval( 'css_minify' ) - && File::isLocal( $href ) - ) { - if ( wpp_in_array( array_keys( Option::get( 'css_minify' ) ), $href ) ) { - $link->href = Minify::resource( $href ); - } - } - - // Defer CSS - if ( - Option::boolval( 'css_defer', false ) - && ! wpp_in_array( Option::get( 'css_file_exclude', [] ), $href ) - ) { - - Collection::add( 'defer', 'css', $link->outertext ); - - $link->rel = 'preload'; - $link->as = 'style'; - $link->onload = "this.rel='stylesheet'"; - - } - - // CDN - if ( - Option::boolval( 'cdn' ) - && File::isLocal( $href ) - && ! wpp_in_array( Option::get( 'cdn_exclude', [] ), $href ) - ) { - $link->href = str_replace( site_url(), Option::get( 'cdn_hostname'), $link->href ); - } - - } - - } - - /** - * Parse JavaScript - * - * @return void - */ - private function parseJS() { - - // Parse scripts - foreach ( $this->html->find( 'script' ) as $script ) { - - if ( - $script->type == 'application/ld+json' - || $script->{'data-skip'} == 'true' - || strstr( $script->src, WPP_ASSET_URL ) - || strstr( $script->src, WPP_ADDONS_URL ) - || ( is_user_logged_in() && strstr( $script->src, 'wp-includes' ) ) - ) { - continue; - } - - - $src = Url::getClean( $script->src ); - - if ( File::isLocal( $src ) ) { - - // Is this a plugin file ? - if ( strstr( $script->src, plugins_url() ) ) { - Collection::add( 'plugin', 'js', $src ); - } else { - Collection::add( 'theme', 'js', $src ); - } - - // Check if resource is disabled - if ( wpp_is_resource_disabled( 'js', $src ) ) { - $script->outertext = ''; - continue; - } - - } else { - - if ( $script->src && ! strstr( $script->src, site_url() ) ) { - - Collection::add( 'external', 'js', $script->src ); - - // Check if external resource is disabled - if ( wpp_is_resource_disabled( 'js', wpp_get_file_clean_name( $script->src ) ) ) { - - $script->outertext = ''; - continue; - - } else { - - Collection::add( 'prefetch', 'js', wpp_get_file_hostname( $script->src ), true ); - - } - - } - - } - - - // Inline JS - if ( wpp_in_array( array_keys( Option::get( 'js_inline', [] ) ), $src ) ) { - - if ( File::isLocal( $src ) ) { - - $code = File::get( File::path( $src ) ); - - // Minify file - if ( wpp_in_array( array_keys( Option::get( 'js_minify', [] ) ), $src ) ) { - $code = Minify::code( $code ); - } - - // Defer ? - $type = Option::boolval( 'js_defer' ) ? 'wppscript' : 'javascript'; - - $script->outertext = ''; - - continue; - - } - - } - - // Combine JS - if ( wpp_in_array( array_keys( Option::get( 'js_combine', [] ) ), $src ) ) { - - if ( File::isLocal( $src ) ) { - - if ( Option::boolval( 'js_defer' ) ) { - - // Exclude file from async loading will exclude also exclude file from combine - if ( ! wpp_in_array( Option::get( 'js_file_exclude', [] ), $src ) ) { - - Collection::add( 'combine', 'js', [ - 'file' => $src - ] ); - - $script->outertext = ''; - } - - } else { - - Collection::add( 'combine', 'js', [ - 'file' => $src - ] ); - - $script->outertext = ''; - - } - - - } elseif ( ! $script->src) { - - Collection::add( 'combine', 'js', [ - 'code' => $script->innertext - ] ); - - $script->outertext = ''; - - } - - continue; - - } - - - // Minify JS - if ( File::isLocal( $src ) ) { - - if ( wpp_in_array( array_keys( Option::get( 'js_minify', [] ) ), $src ) ) { - $script->src = Minify::resource( $src ); - } - - } elseif ( ! $script->src && Option::get( 'js_minify_inline', false ) ) { - - $script->innertext = Minify::code( $script->innertext ); - - } - - // CDN - if ( - Option::boolval( 'cdn' ) - && File::isLocal( $src ) - && ! wpp_in_array( Option::get( 'cdn_exclude', [] ), $src ) - ) { - - if ( $script->src ) { - $script->src = str_replace( site_url(), Option::get( 'cdn_hostname'), $script->src ); - } - - } - - // Defer JS - if ( - Option::boolval( 'js_defer' ) - && ! wpp_in_array( Option::get( 'js_file_exclude', [] ), $src ) - ) { - // set type - $script->type = 'text/wppscript'; - // change src - if ($script->src) { - $script->{'data-src'} = $script->src; - $script->removeAttribute( 'src' ); - } - - } - } - - } - - /** - * Parse images - * - * @return void - */ - private function parseImages() { - - $upload = wp_upload_dir(); - - // Check if images in specific containers are excluded - if ( ! empty( $containers = Option::get( 'images_containers_ids', [] ) ) ) { - - $containers = array_map( 'trim', $containers ); - - foreach( $containers as $container ) { - - if ( empty( $container ) ) continue; - - foreach( $this->html->find( $container . ' img' ) as $img ) { - $img->{'data-skip'} = 'true'; - } - - } - } - - $images = []; - $excluded = Option::get( 'images_exclude', [] ); - - // Get images - foreach( $this->html->find( 'img' ) as $img ) { - - // skip image if it has skip attribute or src is empty and its excluded from admin - if ( - $img->{'data-skip'} === 'true' - || ! $img->src - || wpp_in_array( $excluded, $img->src ) - ) { - continue; - } - - $images[] = $img; - - } - - // load responsive images - if ( - Option::boolval( 'images_resp' ) - && ! empty( $images ) - ) { - - foreach( $images as $img ) { - - // only images from media library - if ( strstr( $img->src, $upload[ 'baseurl' ] ) ) { - - // check image width - if ( ! file_exists( $image = File::path( $img->src ) ) ) { - wpp_log( sprintf( 'Image %s is found on site, but looks like it does not exists', $img->src ) ); - continue; - } - - $size = @getimagesize( $image ); - - // skip images smaller than 640px width - if ( isset( $size[ 0 ] ) && $size[ 0 ] < 640 ) { - continue; - } - - $variations = Image::getAllVariations( $img->src ); - - if ( ! empty( $variations ) ) { - - // Remove attributes - $img->removeAttribute( 'sizes' ); - $img->removeAttribute( 'width' ); - $img->removeAttribute( 'height' ); - $img->srcset = ''; - - foreach ( $variations as $width => $image ) { - $img->srcset .= sprintf( '%s %sw,', $image, $width ); - } - - $img->srcset = rtrim( $img->srcset, ',' ); - - } - - } - - } - - } - - // lazy load images - if ( - Option::boolval( 'images_lazy' ) - && ! empty( $images ) - ) { - - // If lazy load is disabled for mobile devices - if ( wp_is_mobile() && Option::boolval( 'disable_lazy_mobile' ) ) { - return false; - } - - foreach( $images as $img ) { - - $img->loading = 'lazy'; - $img->{'data-srcset'} = $img->srcset; - $img->{'data-src'} = $img->src; - - $img->removeAttribute( 'srcset' ); - - $img->src = WPP_ASSET_URL . 'placeholder.png'; - - } - - } - - // CDN - if ( - Option::boolval( 'cdn' ) - && Option::boolval( 'cdn_hostname') - && ! empty( $images ) - ) { - - foreach( $images as $img ) { - - if ( strstr( $img->src, $upload[ 'baseurl' ] ) || strstr( $img->src, 'data:image' ) ) { - - if ( wpp_in_array( Option::get( 'cdn_exclude', [] ), $img->src ) ) { - continue; - } - - $img->src = str_replace( site_url(), Option::get( 'cdn_hostname'), $img->src ); - - // Responsive - if ( Option::boolval( 'images_resp' ) ) { - $img->srcset = str_replace( site_url(), Option::get( 'cdn_hostname'), $img->srcset ); - } - - // Lazy - if ( Option::boolval( 'images_lazy' ) ) { - $img->{'data-src'} = str_replace( site_url(), Option::get( 'cdn_hostname'), $img->{'data-src'} ); - $img->{'data-srcset'} = str_replace( site_url(), Option::get( 'cdn_hostname'), $img->{'data-srcset'} ); - } - - } - - } - - } - - - } - - - /** - * Parse iframes - * - * @return void - */ - private function parseIframes() { - - // lazy load iframes - foreach( $this->html->find( 'iframe' ) as $iframe ) { - - // skip iframe if it has skip attribute or src is empty - if ( - $iframe->{'data-skip'} === 'true' - || ! $iframe->src - ) { - continue; - } - - $iframe->loading = 'lazy'; - $iframe->{'data-src'} = $iframe->src; - $iframe->src = 'about:blank'; - - } - - } - - /** - * Parse HTML - * - * @return string - */ - private function parseHTML() { - - if ( Option::boolval( 'html_optimization' ) ) { - - $html = new HtmlMin(); - - $html->doSortCssClassNames(false); - $html->doOptimizeAttributes(false); - $html->doSortHtmlAttributes(false); - $html->doRemoveOmittedHtmlTags(false); - $html->doRemoveDeprecatedAnchorName(false); - $html->doRemoveValueFromEmptyInput(false); - $html->doRemoveEmptyAttributes(false); - - if ( ! Option::boolval( 'html_minify_normal' ) ) { - $html->doSumUpWhitespace( false ); - } else { - $html->doRemoveWhitespaceAroundTags(); - } - - if ( Option::boolval( 'html_minify_aggressive' ) ) { - $html->doRemoveSpacesBetweenTags(); - } - - if ( ! Option::boolval( 'html_remove_comments' ) ) { - $html->doRemoveComments( false ); - } - - if ( ! Option::boolval( 'html_remove_link_type' ) ) { - $html->doRemoveDeprecatedTypeFromStylesheetLink( false ); - } - - if ( ! Option::boolval( 'html_remove_script_type' ) ) { - $html->doRemoveDeprecatedTypeFromScriptTag( false ); - } - - if ( ! Option::boolval( 'html_remove_qoutes' ) ) { - $html->doRemoveOmittedQuotes( false ); - } - - return $html->minify( $this->html->innertext ); - - } - - - return $this->html->innertext; - - } - - /** - * Rebuild the template - * - * @return void - */ - private function buildTemplate() { - - // Build lists - foreach( [ 'theme', 'plugin', 'external', 'prefetch', 'critical' ] as $list ) { - - foreach( Collection::get( $list ) as $type => $items ) { - - $option = sprintf( '%s_%s_list', $list, $type ); - - $data = Option::get( $option, [] ); - - foreach( $items as $item ) { - - if ( ! in_array( $item, $data ) ) { - $data[] = $item; - } - - } - - Option::update( $option, $data ); - - } - - } - - - if ( - Option::boolval( 'css_defer' ) - && boolval( trim( Option::get( 'css_custom_path_def' ) ) ) - ) { - // custom css path - $this->head->innertext - .= '' - . PHP_EOL; - - } - - - // Combined css files - if ( ! empty( $combined_css = Collection::get( 'combine', 'css' ) ) ) { - - // combine css links grouped by media - $linksMedia = []; - - foreach ( $combined_css as $link ) { - $linksMedia[ $link[ 'href' ] ] = $link[ 'media' ]; - } - - foreach ( array_unique( $linksMedia ) as $media ) { - - $filename = md5( $media . serialize( $linksMedia ) ) . '.css'; - - if ( ! file_exists( WPP_CACHE_DIR . $filename ) ) { - - $code = ''; - - foreach ( $combined_css as $link ) { - - if ( $link[ 'media' ] == $media ) { - - $originalCode = File::get( File::path( $link[ 'href' ] ) ); - - if ( - Option::get( 'css_minify' ) - && wpp_in_array( array_keys( Option::get( 'css_minify' ) ), $link[ 'href' ] ) - ) { - $code .= Minify::code( $originalCode, $link[ 'href' ] ); - } else { - $code .= Minify::replacePaths( $originalCode, $link[ 'href' ] ); - } - - } - } - - File::save( WPP_CACHE_DIR . $filename, $code ); - - } - - //touch( WPP_CACHE_DIR . $filename, time() - 3600 ); - - // CDN? - $url = ( Option::get( 'cdn' ) && Option::get( 'cdn_hostname' ) ) - ? str_replace( site_url(), Option::get( 'cdn_hostname' ), WPP_CACHE_URL ) - : WPP_CACHE_URL; - - if ( Option::boolval( 'css_defer' ) ) { - $stylesheet = ''; - // fallback - Collection::add( 'defer', 'css', '' ); - } else { - $stylesheet = ''; - } - - $this->head->innertext .= $stylesheet . PHP_EOL; - - } - - } - - // Combine Google fonts - if ( ! empty( $google_fonts = Collection::get( 'combine', 'google_fonts' ) ) ) { - - $href = '//fonts.googleapis.com/css?family=' . implode( '|', $google_fonts ); - - // Google fonts display - if ( Option::get( 'css_font_display' ) !== 'none' ) { - - $url = parse_url( htmlspecialchars_decode( $href ) ); - - parse_str( $url['query'], $parameters ); - - $parameters['display'] = Option::get( 'css_font_display' ); - - $href= '//fonts.googleapis.com/css?'. http_build_query( $parameters ); - - } - - if ( Option::boolval( 'css_defer' ) ) { - - $stylesheet = ''; - // fallback - Collection::add( 'defer', 'css', '' ); - - } else { - $stylesheet = ''; - } - - $this->head->innertext .= $stylesheet . PHP_EOL; - - } - - // combined js files - if ( ! empty( $combined_js = Collection::get( 'combine', 'js' ) ) ) { - - $filename = md5( serialize( $combined_js ) ) . '.js'; - - // Check if combined file exists - if ( ! file_exists( WPP_CACHE_DIR . $filename ) ) { - - $code = ''; - - foreach ( $combined_js as $scripts ) { - // proccess by type - foreach ( $scripts as $type => $script ) { - - if ( $type == 'file' ) { - - $extension = pathinfo( $script , PATHINFO_EXTENSION ); - - $originalCode = ( $extension == 'php' ) - ? wp_remote_retrieve_body( wp_remote_get( $script ) ) - : File::get( File::path( $script ) ); - - $code .= wpp_in_array( array_keys( Option::get( 'js_minify', [] ) ), $script ) - ? Minify::code( $originalCode ) - : $originalCode; - - } else { - $code .= Minify::code( $script ); - } - // ASI - $code .= ';' . PHP_EOL; - } - - } - - File::save( WPP_CACHE_DIR . $filename, $code ); - - } - - // CDN? - $url = ( Option::get( 'cdn' ) && Option::get( 'cdn_hostname' ) ) - ? str_replace( site_url(), Option::get( 'cdn_hostname' ), WPP_CACHE_URL ) - : WPP_CACHE_URL; - - // Defer js - if ( Option::boolval( 'js_defer' ) ) { - $this->body->innertext .= '' . PHP_EOL; - } else { - $this->body->innertext .= '' . PHP_EOL; - } - - } - - // Insert noscript fallback - if ( ! empty( $defered_css = Collection::get( 'defer', 'css' ) ) ) { - $this->head->innertext .= '' . PHP_EOL; - } - - // Prefetch - $prefetch = array_unique( - array_merge( - Option::get( 'js_prefetch', [] ), - Option::get( 'css_prefetch', [] ) - ) - ); - - if ( ! empty( $prefetch ) ) { - - $included = []; - - foreach( $this->html->find( 'link[rel=dns-prefetch]' ) as $link ) { - $included[] = $link->href; - } - - foreach( array_keys( $prefetch ) as $dns ) { - if ( ! wpp_in_array( $dns, $included ) ) { - $this->head->innertext = '' . PHP_EOL . $this->head->innertext; - } - } - - } - - // Preconnect - $preconnect = array_unique( - array_merge( - Option::get( 'js_preconnect', [] ), - Option::get( 'css_preconnect', [] ) - ) - ); - - if ( ! empty( $preconnect ) ) { - - $included = []; - - foreach( $this->html->find( 'link[rel=preconnect]' ) as $link ) { - $included[] = $link->href; - } - - foreach( array_keys( $preconnect ) as $dns ) { - if ( ! wpp_in_array( $dns, $included ) ) { - $this->head->innertext = '' . PHP_EOL . $this->head->innertext; - } - } - - } - - $vars = [ - 'css' => Option::boolval( 'css_defer' ), - 'js' => Option::boolval( 'js_defer' ), - 'images' => Option::boolval( 'images_lazy' ), - 'videos' => Option::boolval( 'videos_lazy' ) - ]; - - // Clear cache - if ( Option::boolval( 'cache' ) ) { - $vars[ 'expire' ] = time() + intval( Option::get( 'cache_time', 3600 ) * Option::get( 'cache_length', 24 ) ); - $vars[ 'ajax_url' ] = admin_url( 'admin-ajax.php'); - } - - // WPP JS - $this->body->innertext .= '' . PHP_EOL; - - - /** - * Exclude URL from HTML optimization filter - * @since 1.1.8 - */ - $html_url_exclude = apply_filters( 'wpp_html_url_exclude', Option::get( 'html_url_exclude', [] ) ); - - if ( ! wpp_is_url_excluded( Url::current(), $html_url_exclude ) ) { - /** - * Filter parsed content - * - * @since 1.0.8 - */ - $this->html = apply_filters( 'wpp_parsed_content', $this->parseHTML() ); - } - - - // Footprint - $this->html .= PHP_EOL . sprintf( '', __( 'Optimized by', 'wpp' ), WPP_PLUGIN_NAME, WPP_VERSION ) . PHP_EOL; - - } - - /** - * Save cache file - * - * @return void - */ - private function saveCache() { - - /** - * Filter excluded urls - * - * @since 1.0.0 - */ - $excluded = apply_filters( 'wpp_exclude_urls', Option::get( 'cache_url_exclude', [] ) ); - - // Check if page is excluded - if ( ! wpp_is_url_excluded( Url::current(), $excluded ) ) { - - if ( ! $this->is_amp() ) { - - $this->html .= sprintf( - '', - number_format( ( microtime( true ) - $this->time ), 2 ), - date( get_option( 'date_format' ) ), - date( get_option( 'time_format' ) ) - ); - - } - - Cache::save( $this->html, $this->is_amp() ); - - } - - } - - - /** - * Check if current template is an AMP template - * - * @return boolean - */ - private function is_amp() { - - if ( ! is_null( static::$amp ) ) - return static::$amp; - - static::$amp = ( - $this->htmltag - && isset( $this->htmltag->{'⚡'} ) - || isset( $this->htmltag->amp ) - ) ? true : false; - - return static::$amp; - - } - - - /** - * Return html content - * - * @return string - * @since 1.0.9 - */ - public function __toString() { - return strval( $this->html ); - } - -} \ No newline at end of file diff --git a/includes/classes/ui.php b/includes/classes/ui.php deleted file mode 100644 index b61f043..0000000 --- a/includes/classes/ui.php +++ /dev/null @@ -1,193 +0,0 @@ - -* @package WPP -*/ - -class UI -{ - - /** - * Top bar links - * - * @var array - * @since 1.1.0 - */ - private static $links = []; - - /** - * WPP pages - * - * @var array - * @since 1.1.0 - */ - private static $pages = []; - - - /** - * Add WPP page - * - * @param string $id - * @param string $name - * @param string $template - * @return void - * @since 1.1.0 - */ - public static function addPage( $id, $name, $template ) { - - static::$pages[ $id ] = [ - 'name' => $name, - 'template' => $template - ]; - - } - - - /** - * Add top-bar link - * - * @param string $id - * @param string $title - * @param string $href - * @param array $attributes - * @return void - * @since 1.1.0 - */ - public static function addLink( $id, $title, $href = null, $attributes = [] ) { - - $attributes = wp_parse_args( $attributes, [ - 'id' => $id, - 'class' => '' - ] ); - - static::$links[ $id ] = [ - 'title' => $title, - 'href' => $href, - 'attributes' => $attributes - ]; - - } - - - /** - * Remove registered page - * - * @param string $id - * @return void - * @since 1.1.0 - */ - public static function removePage( $id ) { - - if ( array_key_exists( $id, static::$pages) ) { - unset( static::$pages[ $id ] ); - } - - } - - - /** - * Remove registered top-bar link - * - * @param string $id - * @return void - * @since 1.1.0 - */ - public static function removeLink( $id ) { - - if ( array_key_exists( $id, static::$links) ) { - unset( static::$links[ $id ] ); - } - - } - - - /** - * Get registered pages - * - * @return array - * @since 1.1.0 - */ - public static function getPages() { - return static::$pages; - } - - - /** - * Get registered top-bar links - * - * @return array - * @since 1.1.0 - */ - public static function getLinks() { - return static::$links; - } - - - /** - * Register WPP pages and top-bar links - * - * @return void - * @since 1.1.0 - */ - public static function register() { - - // Register pages - foreach( static::getPages() as $id => $data ) { - - // WPP tab - add_action( 'wpp-admin-menu', function() use( $id, $data ) { - echo '
  • ' . $data[ 'name' ] . '
  • '; - } ); - - // WPP mobile option - add_action( 'wpp-admin-menu-mobile', function() use( $id, $data ) { - echo ''; - } ); - - // WPP tab content - add_action( 'wpp-admin-page-content', function() use( $data ) { - - if ( file_exists( $data[ 'template' ] ) ) { - include $data[ 'template' ]; - } else { - wpp_log( sprintf( 'Template %s not exists', $data[ 'template' ] ) ); - } - - } ); - - } - - - // Register top bar items - foreach( static::getLinks() as $id => $data ) { - - add_action( 'wpp-admin-bar', function( $admin_bar ) use( $id, $data ) { - - $href = is_null( $data[ 'href' ] ) - ? admin_url( 'admin.php?page=' . WPP_PLUGIN_ADMIN_URL . '&wpp-tab=' . $id ) - : $data[ 'href' ]; - - $admin_bar->add_node( [ - 'id' => $data[ 'attributes' ][ 'id' ], - 'title' => $data[ 'title' ], - 'href' => $href, - 'parent' => 'wpp', - 'meta' => [ - 'class' => $data[ 'attributes' ][ 'class' ], - 'title' => $data[ 'title' ] - ] - ] ); - - } ); - - } - - } - -} \ No newline at end of file diff --git a/includes/classes/url.php b/includes/classes/url.php deleted file mode 100644 index f88d694..0000000 --- a/includes/classes/url.php +++ /dev/null @@ -1,59 +0,0 @@ - -* @package WPP -*/ - -class Url -{ - /** - * Get absolute url file path - * - * @since 1.0.0 - * @param string $file - * - * @return string - */ - public static function path( $file ) { - return str_replace( [ realpath( ABSPATH ), DIRECTORY_SEPARATOR ], [ site_url(), '/' ], $file ); - } - - - /** - * Get current url - * - * @since 1.0.0 - * @return string - */ - public static function current() { - return ( is_ssl() ? 'https' : 'http' ) . '://' . Input::server( 'HTTP_HOST' ) . Input::server( 'REQUEST_URI' ); - } - - - /** - * Get clean file path - * - * @since 1.0.0 - * @param string $path - * - * @return string - */ - public static function getClean( $path ) - { - - if ( strpos( $path, '//' ) === 0) { - - $info = parse_url( site_url() ); - - if ( strstr( $path, $info[ 'host' ] ) ) { - $path = $info[ 'scheme' ] . ':' . $path; - } - - } - - return str_replace( [ trailingslashit( site_url() ), '../' ], '', strtok( $path, '?' ) ); - } - -} \ No newline at end of file diff --git a/includes/classes/wpp.php b/includes/classes/wpp.php deleted file mode 100644 index a9a8d1d..0000000 --- a/includes/classes/wpp.php +++ /dev/null @@ -1,146 +0,0 @@ - -* @package WPP -*/ - -final class WP_Performance -{ - /** - * @var WP_Performance class instance - * @since 1.0.0 - */ - private static $instance; - - /** - * Instantiate the plugin - * - * @since 1.0.0 - * @return void - */ - private function __construct() { - - // Autoloader - require WPP_DIR . 'vendor/autoload.php'; - - /** - * WPP init actions hook - * - * @since 1.1.5.1 - */ - do_action( 'wpp_init' ); - - } - - /** - * Throw error on object clone - * - * @since 1.0.0 - * @return void - */ - public function __clone() { - _doing_it_wrong( - __FUNCTION__, - 'Cloning instances of the class is forbidden', - '1.0.0' - ); - } - - /** - * Disable unserializing of the class - * - * @since 1.1.0 - * @return void - */ - public function __wakeup() { - _doing_it_wrong( - __FUNCTION__, - 'Unserializing instances of the class is forbidden', - '1.0.0' - ); - } - - - /** - * WP Performance initialize - * - * @return WPP - */ - public static function instance() { - - if ( is_null( static::$instance ) ) { - static::$instance = new static(); - } - - return static::$instance; - - } - - /** - * Run WP Performance - * - */ - public function run() { - - // Don't run in CLI - if ( ! defined( 'WP_CLI' ) ) { - return is_admin() - ? $this->backend() - : $this->frontend(); - } - - } - - /** - * WP Performance front-end actions - * @since 1.0.0 - */ - private function frontend() { - - // Is plugin disabled - if ( Option::boolval( 'wpp_disable' ) ) - return false; - - /** - * Frontend actions hook - * - * @since 1.0.8 - */ - do_action( 'wpp_frontend_init' ); - - } - - /** - * WP Performance back-end actions - * @since 1.0.0 - */ - private function backend() { - - // Register WP plugin hooks - register_activation_hook( - WPP_SELF, - 'wpp_activate' - ); - - register_deactivation_hook( - WPP_SELF, - 'wpp_deactivate' - ); - - register_uninstall_hook( - WPP_SELF, - 'wpp_uninstall' - ); - - /** - * Backend actions hook - * - * @since 1.1.5.1 - */ - do_action( 'wpp_backend_init' ); - - } - -} \ No newline at end of file diff --git a/includes/data/definitions/.htaccess b/includes/data/definitions/.htaccess deleted file mode 100644 index 14249c5..0000000 --- a/includes/data/definitions/.htaccess +++ /dev/null @@ -1 +0,0 @@ -Deny from all \ No newline at end of file diff --git a/includes/data/definitions/cache.apache.txt b/includes/data/definitions/cache.apache.txt deleted file mode 100644 index 1a906fa..0000000 --- a/includes/data/definitions/cache.apache.txt +++ /dev/null @@ -1,43 +0,0 @@ - -# WPP Cache load start - - -Header append Vary: Accept-Encoding - - - - AddType text/html .html_gz .html_mobile_gz .html_amp_gz .html_mobile_amp_gz - AddEncoding gzip .html_gz .html_mobile_gz .html_amp_gz .html_mobile_amp_gz - - - SetEnvIfNoCase Request_URI \.html_gz$ no-gzip - SetEnvIfNoCase Request_URI \.html_amp_gz$ no-gzip - SetEnvIfNoCase Request_URI \.html_mobile_gz$ no-gzip - SetEnvIfNoCase Request_URI \.html_mobile_amp_gz$ no-gzip - - - - - RewriteEngine On - RewriteBase {BASEDIR} - RewriteCond %{HTTP_USER_AGENT} Mobile [NC] - RewriteCond %{HTTP_USER_AGENT} Android [NC] - RewriteCond %{HTTP_USER_AGENT} Kindle [NC] - RewriteCond %{HTTP_USER_AGENT} BlackBerry [NC] - RewriteCond %{HTTP_USER_AGENT} Opera\sMini [NC] - RewriteCond %{HTTP_USER_AGENT} Opera\sMobi [NC] - RewriteRule .* - [E=WPP_MOBILE_EXT:_mobile] - RewriteCond %{REQUEST_URI} /{AMP_TAG}/$ [NC] - RewriteRule .* - [E=WPP_AMP_EXT:_amp] - RewriteCond %{HTTP:Accept-Encoding} gzip - RewriteRule .* - [E=WPP_GZIP_EXT:_gz] - RewriteCond %{REQUEST_METHOD} GET - RewriteCond %{QUERY_STRING} ="" - RewriteCond %{REQUEST_URI} !^(/wp-json/(.*))$ [NC] - RewriteCond %{HTTP:Cookie} !(wordpress_logged_in_|wp-postpass_|wptouch_switch_toggle|comment_author_|comment_author_email_) [NC] - {USER_AGENTS} - RewriteCond "%{DOCUMENT_ROOT}{BASEDIR}{CONTENT_DIR}/cache/wpp-cache/%{HTTP_HOST}%{REQUEST_URI}/index.html%{ENV:WPP_MOBILE_EXT}%{ENV:WPP_AMP_EXT}%{ENV:WPP_GZIP_EXT}" -f - RewriteRule .* "{BASEDIR}{CONTENT_DIR}/cache/wpp-cache/%{HTTP_HOST}%{REQUEST_URI}/index.html%{ENV:WPP_MOBILE_EXT}%{ENV:WPP_AMP_EXT}%{ENV:WPP_GZIP_EXT}" [L] - - -# WPP Cache load end diff --git a/includes/data/definitions/cache.nginx.txt b/includes/data/definitions/cache.nginx.txt deleted file mode 100644 index 71c70e7..0000000 --- a/includes/data/definitions/cache.nginx.txt +++ /dev/null @@ -1,57 +0,0 @@ -# WPP Cache load start - -set $wpp_cache 1; -set $wpp_mobile 1; -set $wpp_amp 1; - -if ($request_method = POST){ - set $wpp_cache 0; -} - -if ($is_args) { - set $wpp_cache 0; -} - -if (-f "$document_root/.maintenance") { - set $wpp_cache 0; -} - -if ($http_cookie ~* (wordpress_logged_in_|wp\-postpass_|wptouch_switch_toggle|comment_author_|comment_author_email_)) { - set $wpp_cache 0; -} - -if (!-f "{CACHEDIR}$http_host/$request_uri/index.html") { - set $wpp_cache 0; -} - -if (!-f "{CACHEDIR}$http_host/$request_uri/index.html_mobile") { - set $wpp_mobile 0; -} - -{USER_AGENTS} - -if ($http_user_agent ~* (Mobile|Android|Kindle|BlackBerry|Opera+Mini|Opera+Mobi)) { - set $wpp_cache "{$wpp_cache}{$wpp_mobile}"; -} - -if ($request_uri ~* /{AMP_TAG}/$) { - set $wpp_cache "{$wpp_cache}{$wpp_mobile}{$wpp_amp}"; -} - -if ($wpp_cache = 111){ - rewrite .* /{CONTENT_DIR}/cache/{CACHEDIR_BASENAME}/$http_host/$request_uri/index.html_mobile_amp last; -} - -if ($wpp_cache = 101){ - rewrite .* /{CONTENT_DIR}/cache/{CACHEDIR_BASENAME}/$http_host/$request_uri/index.html_amp last; -} - -if ($wpp_cache = 11){ - rewrite .* /{CONTENT_DIR}/cache/{CACHEDIR_BASENAME}/$http_host/$request_uri/index.html_mobile last; -} - -if ($wpp_cache = 1){ - rewrite .* /{CONTENT_DIR}/cache/{CACHEDIR_BASENAME}/$http_host/$request_uri/index.html last; -} - -# WPP Cache load end \ No newline at end of file diff --git a/includes/data/definitions/expire.apache.txt b/includes/data/definitions/expire.apache.txt deleted file mode 100644 index fe6278a..0000000 --- a/includes/data/definitions/expire.apache.txt +++ /dev/null @@ -1,74 +0,0 @@ - -# WPP Expire start - - - Header unset ETag - - -FileETag None - - - - - - SetEnvIf Origin ":" IS_CORS - Header set Access-Control-Allow-Origin "*" env=IS_CORS - - - - - Header append Vary: Accept-Encoding - - - - - - - Header set Access-Control-Allow-Origin "*" - - - - - ExpiresActive on - ExpiresDefault "access plus 1 month" - ExpiresByType text/css "access plus 1 year" - ExpiresByType application/atom+xml "access plus 1 hour" - ExpiresByType application/rdf+xml "access plus 1 hour" - ExpiresByType application/rss+xml "access plus 1 hour" - ExpiresByType application/json "access plus 0 seconds" - ExpiresByType application/ld+json "access plus 0 seconds" - ExpiresByType application/schema+json "access plus 0 seconds" - ExpiresByType application/vnd.geo+json "access plus 0 seconds" - ExpiresByType application/xml "access plus 0 seconds" - ExpiresByType text/xml "access plus 0 seconds" - ExpiresByType image/vnd.microsoft.icon "access plus 1 week" - ExpiresByType image/x-icon "access plus 1 week" - ExpiresByType text/html "access plus 0 seconds" - ExpiresByType application/javascript "access plus 1 year" - ExpiresByType application/x-javascript "access plus 1 year" - ExpiresByType text/javascript "access plus 1 year" - ExpiresByType application/manifest+json "access plus 1 week" - ExpiresByType application/x-web-app-manifest+json "access plus 0 seconds" - ExpiresByType text/cache-manifest "access plus 0 seconds" - ExpiresByType audio/ogg "access plus 1 month" - ExpiresByType image/bmp "access plus 1 month" - ExpiresByType image/gif "access plus 1 month" - ExpiresByType image/jpeg "access plus 1 month" - ExpiresByType image/png "access plus 1 month" - ExpiresByType image/svg+xml "access plus 1 month" - ExpiresByType image/webp "access plus 1 month" - ExpiresByType video/mp4 "access plus 1 month" - ExpiresByType video/ogg "access plus 1 month" - ExpiresByType video/webm "access plus 1 month" - ExpiresByType application/vnd.ms-fontobject "access plus 1 month" - ExpiresByType font/eot "access plus 1 month" - ExpiresByType font/opentype "access plus 1 month" - ExpiresByType application/x-font-ttf "access plus 1 month" - ExpiresByType application/font-woff "access plus 1 month" - ExpiresByType application/x-font-woff "access plus 1 month" - ExpiresByType font/woff "access plus 1 month" - ExpiresByType application/font-woff2 "access plus 1 month" - ExpiresByType text/x-cross-domain-policy "access plus 1 week" - - -# WPP Expire end diff --git a/includes/data/definitions/expire.nginx.txt b/includes/data/definitions/expire.nginx.txt deleted file mode 100644 index f1c3c05..0000000 --- a/includes/data/definitions/expire.nginx.txt +++ /dev/null @@ -1,7 +0,0 @@ -# WPP Expire start - -location ~* \.(css|js|ico|gif|jpeg|jpg|webp|png|svg|eot|otf|woff|woff2|ttf|ogg|pdf)$ { - expires 30d; -} - -# WPP Expire end diff --git a/includes/data/definitions/gzip.apache.txt b/includes/data/definitions/gzip.apache.txt deleted file mode 100644 index 7923edc..0000000 --- a/includes/data/definitions/gzip.apache.txt +++ /dev/null @@ -1,54 +0,0 @@ - -# WPP GZIP start - - - - SetOutputFilter DEFLATE - - - - SetEnvIfNoCase ^(Accept-EncodXng|X-cept-Encoding|X{15}|~{15}|-{15})$ ^((gzip|deflate)\s*,?\s*)+|[X~-]{4,13}$ HAVE_Accept-Encoding - RequestHeader append Accept-Encoding "gzip,deflate" env=HAVE_Accept-Encoding - SetEnvIfNoCase Request_URI \ - \.(?:gif|jpe?g|png|rar|zip|exe|flv|mov|wma|mp3|avi|swf|mp?g|mp4|webm|webp|pdf)$ no-gzip dont-vary - - - - - AddOutputFilterByType DEFLATE text/plain - AddOutputFilterByType DEFLATE text/html - AddOutputFilterByType DEFLATE text/xml - AddOutputFilterByType DEFLATE text/css - - AddOutputFilterByType DEFLATE application/xml - AddOutputFilterByType DEFLATE application/xhtml+xml - AddOutputFilterByType DEFLATE application/rss+xml - AddOutputFilterByType DEFLATE application/javascript - AddOutputFilterByType DEFLATE application/x-javascript - AddOutputFilterByType DEFLATE application/json - AddOutputFilterByType DEFLATE application/ld+json - AddOutputFilterByType DEFLATE application/manifest+json - AddOutputFilterByType DEFLATE application/schema+json - AddOutputFilterByType DEFLATE application/rss+xml - AddOutputFilterByType DEFLATE application/rdf+xml - AddOutputFilterByType DEFLATE application/x-font-ttf - AddOutputFilterByType DEFLATE x-web-app-manifest+json - - AddOutputFilterByType DEFLATE font/collection - AddOutputFilterByType DEFLATE font/eot - AddOutputFilterByType DEFLATE font/opentype - AddOutputFilterByType DEFLATE font/otf - AddOutputFilterByType DEFLATE font/ttf - - AddOutputFilterByType DEFLATE image/bmp - AddOutputFilterByType DEFLATE image/svg+xml - AddOutputFilterByType DEFLATE image/vnd.microsoft.icon - AddOutputFilterByType DEFLATE image/x-icon - - - - AddEncoding gzip svgz - - - -# WPP GZIP end diff --git a/includes/data/definitions/gzip.nginx.txt b/includes/data/definitions/gzip.nginx.txt deleted file mode 100644 index f91cf3b..0000000 --- a/includes/data/definitions/gzip.nginx.txt +++ /dev/null @@ -1,11 +0,0 @@ -# WPP GZIP start - -gzip on; -gzip_vary on; -gzip_proxied any; -gzip_comp_level 6; -gzip_buffers 16 8k; -gzip_http_version 1.1; -gzip_types image/svg+xml text/plain text/html text/xml text/css text/javascript application/xml application/xhtml+xml application/rss+xml application/javascript application/x-javascript application/x-font-ttf application/vnd.ms-fontobject font/opentype font/ttf font/eot font/otf; - -# WPP GZIP end diff --git a/includes/data/definitions/index.php b/includes/data/definitions/index.php deleted file mode 100644 index e71af0e..0000000 --- a/includes/data/definitions/index.php +++ /dev/null @@ -1 +0,0 @@ - -* @package WPP -*/ - -use WPP\Option; - -/** - * WPP Init actions - */ -add_action( 'wpp_init', function(){ - - // Load language - load_plugin_textdomain( - 'wpp', - false, - plugin_basename( WPP_DIR ) . '/languages' - ); - - // Schedule cron tasks - - // Register schedules - add_filter( - 'cron_schedules', - 'wpp_get_cron_schedules' - ); - - // Sitemaps cache preload - if ( Option::get( 'sitemaps_list' ) ) { - - add_action( - 'wpp_prepare_preload', - 'wpp_cron_prepare_preload' - ); - - add_action( - 'wpp_preload_cache', - 'wpp_cron_preload_cache' - ); - - // Prepare preload - if ( ! wp_next_scheduled( 'wpp_prepare_preload' ) ) { - wp_schedule_event( - time(), - 'wpp_every_5_minutes', - 'wpp_prepare_preload' - ); - } - - // Preload cache - if ( ! wp_next_scheduled( 'wpp_preload_cache' ) ) { - wp_schedule_event( - time(), - 'wpp_every_minute', - 'wpp_preload_cache' - ); - } - - } - - // Database cleanup - if ( $frequency = Option::get( 'db_cleanup_frequency' ) ) { - - add_action( - 'wpp_db_cleanup', - 'wpp_cron_db_cleanup' - ); - - if ( ! wp_next_scheduled( 'wpp_db_cleanup' ) ) { - wp_schedule_event( - time(), - $frequency, - 'wpp_db_cleanup' - ); - } - - } - - -} ); \ No newline at end of file diff --git a/includes/functions/admin.php b/includes/functions/admin.php deleted file mode 100644 index 745ca51..0000000 --- a/includes/functions/admin.php +++ /dev/null @@ -1,380 +0,0 @@ - -* @package WPP -*/ - -use WPP\Input; -use WPP\Option; - -/** -* Print admin notice -* -* @since 1.0.0 -* @param string $msg -* @param string $type -* @param boolean $preformatted -* -* @return void -*/ -function wpp_notify( $msg, $type = 'success', $preformatted = true ) { - - add_action( 'admin_notices', function() use ( $msg, $type, $preformatted ){ - - if ( $preformatted ) { - echo '

    ' . __( ucfirst( $type ), 'wpp' ) . ': ' . __( $msg, 'wpp' ) . '

    '; - } else { - echo '

    ' . $msg . '

    '; - } - - } ); - -} - - -/** -* Check option against the value, print selected if true -* -* @since 1.0.0 -* @param mixed $name -* @param mixed $value -* @param mixed $default -* @return void -*/ -function wpp_selected( $name, $value, $default = false ) { - - if ( Option::get( $name, $default ) == $value ) { - echo ' selected'; - } - -} - - -/** - * Check option, print checked if true - * - * @since 1.0.0 - * @param string $name - * @param boolean $default - * @return void - */ -function wpp_checked( $name, $default = false ) { - - if ( Option::boolval( $name, $default ) ) { - echo ' checked'; - } - -} - - -/** - * Is tab active - * - * @since 1.0.0 - * @param string $tab - * @param boolean $default - * @param string $output - * @return string - */ -function wpp_active( $tab, $default = false, $output = 'active' ) { - - if( Input::request( 'wpp-tab' ) == $tab ) { - - echo $output; - - } else { - - if ( Input::get( 'load' ) ) { - if ( $tab == 'settings' ) echo $output; - } else if ( Input::get( 'clear' ) ) { - if ( $tab == Input::get( 'clear' ) ) echo $output; - } else { - if ( $default && ! Input::request( 'wpp-tab' ) ) echo $output; - } - - } - -} - -/** - * Add menu item and register menu page - * - * @return void - * @since 1.0.0 - */ -function wpp_add_menu_item() { - - add_menu_page( WPP_PLUGIN_NAME, WPP_PLUGIN_NAME, 'manage_options', WPP_PLUGIN_ADMIN_URL, function() { - include WPP_ADMIN_DIR . 'admin.php'; - }, 'dashicons-performance' ); - -} - - -/** - * Add wpp admin menu - * - * @since 1.0.0 - * @return void - */ -function wpp_add_top_menu_item() { - - // Insert scripts - if ( ! is_admin() ) { - - add_action( 'wp_enqueue_scripts', function() { - - wp_enqueue_style( 'wpp-overlay', WPP_ASSET_URL . 'overlay.css' ); - wp_enqueue_script( 'wpp-cache-js', WPP_ASSET_URL . 'cache.js', [ 'jquery' ], null, true ); - wp_localize_script( 'wpp-cache-js', 'WPP', [ - 'path' => WPP_ASSET_URL, - 'ajax_url' => admin_url( 'admin-ajax.php' ) - ] ); - - }); - - } - - // Add top bar link - add_action( 'admin_bar_menu', function( $admin_bar ) { - - $admin_bar->add_node( [ - 'id' => 'wpp', - 'title' => '' . WPP_PLUGIN_NAME . '', - 'href' => admin_url( 'admin.php?page=' . WPP_PLUGIN_ADMIN_URL ), - 'meta' => [ - 'class' => 'wpp_toolbar_link', - 'title' => WPP_PLUGIN_NAME - ] - ] ); - - $admin_bar->add_node( [ - 'id' => 'wpp_clear_cache', - 'title' => __( 'Clear cache', 'wpp' ), - 'href' => '#', - 'parent' => 'wpp', - 'meta' => [ - 'class' => 'wpp_clear_cache', - 'title' => __( 'Clear cache', 'wpp' ) - ] - ] ); - - $admin_bar->add_node( [ - 'id' => 'wpp_cache_topbar_link', - 'title' => __( 'Cache', 'wpp' ), - 'href' => admin_url( 'admin.php?page=' . WPP_PLUGIN_ADMIN_URL ), - 'parent' => 'wpp', - 'meta' => [ - 'title' => __( 'Settings', 'wpp' ) - ] - ] ); - - $admin_bar->add_node( [ - 'id' => 'wpp_css_topbar_link', - 'title' => 'CSS', - 'href' => admin_url( 'admin.php?page=' . WPP_PLUGIN_ADMIN_URL . '&wpp-tab=css' ), - 'parent' => 'wpp', - 'meta' => [ - 'title' => 'CSS' - ] - ] ); - - $admin_bar->add_node( [ - 'id' => 'wpp_js_topbar_link', - 'title' => 'JavaScript', - 'href' => admin_url( 'admin.php?page=' . WPP_PLUGIN_ADMIN_URL . '&wpp-tab=javascript' ), - 'parent' => 'wpp', - 'meta' => [ - 'title' => 'JavaScript' - ] - ] ); - - $admin_bar->add_node( [ - 'id' => 'wpp_media_topbar_link', - 'title' => __( 'Media', 'wpp' ), - 'href' => admin_url( 'admin.php?page=' . WPP_PLUGIN_ADMIN_URL . '&wpp-tab=media' ), - 'parent' => 'wpp', - 'meta' => [ - 'title' => __( 'Media', 'wpp' ) - ] - ] ); - - $admin_bar->add_node( [ - 'id' => 'wpp_database_topbar_link', - 'title' => __( 'Database', 'wpp' ), - 'href' => admin_url( 'admin.php?page=' . WPP_PLUGIN_ADMIN_URL . '&wpp-tab=database' ), - 'parent' => 'wpp', - 'meta' => [ - 'title' => __( 'Database', 'wpp' ) - ] - ] ); - - $admin_bar->add_node( [ - 'id' => 'wpp_db_topbar_link', - 'title' => 'CDN', - 'href' => admin_url( 'admin.php?page=' . WPP_PLUGIN_ADMIN_URL . '&wpp-tab=cdn' ), - 'parent' => 'wpp', - 'meta' => [ - 'title' => 'CDN' - ] - ] ); - - $admin_bar->add_node( [ - 'id' => 'wpp_settings_topbar_link', - 'title' => __( 'Settings', 'wpp' ), - 'href' => admin_url( 'admin.php?page=' . WPP_PLUGIN_ADMIN_URL . '&wpp-tab=settings' ), - 'parent' => 'wpp', - 'meta' => [ - 'title' => __( 'Settings', 'wpp' ) - ] - ] ); - - $admin_bar->add_node( [ - 'id' => 'wpp_addons_topbar_link', - 'title' => __( 'Add-ons', 'wpp' ), - 'href' => admin_url( 'admin.php?page=' . WPP_PLUGIN_ADMIN_URL . '&wpp-tab=addons' ), - 'parent' => 'wpp', - 'meta' => [ - 'title' => __( 'Add-ons', 'wpp' ) - ] - ] ); - - /** - * Add WPP top bar items - * @since 1.1.0 - */ - do_action( 'wpp-admin-bar', $admin_bar ); - - - }, 99 ); - -} - - -/** - * Add disable/enable link in plugins list - * - * @param array $links - * @return void - * @since 1.0.0 - */ -function wpp_add_disable_link( $links ) { - - if ( Option::boolval( 'wpp_disable' ) ) { - $action = 'enable'; - $status = __( 'Enable', 'wpp' ); - } else { - $action = 'disable'; - $status = __( 'Temporarily disable', 'wpp' ); - } - - array_push( $links, '' . $status . '' ); - - return $links; - -} - - -/** - * Add WPP metabox - * - * @return void - * @since 1.0.3 - */ -function wpp_add_metabox() { - - add_meta_box( - 'wpp_page_cache_metabox', - sprintf( '%s %s', WPP_PLUGIN_NAME, __( 'Settings', 'wpp' ) ), - 'wpp_display_cache_metabox', - null, - 'side', - 'high' - ); - -} - -/** - * Display metabox - * - * @param WP_Post $post - * @return void - * @since 1.0.3 - */ -function wpp_display_cache_metabox( $post ) { - include WPP_ADMIN_DIR . 'metabox.php'; -} - - - -/** - * Determine if exclude options needs to be shown - * - * @param string $type - * @return boolean - * @since 1.0.3 - */ -function wpp_maybe_show_exclude_option( $type ) { - - if ( ! in_array( $type, [ 'js', 'css' ] ) ) { - return false; - } - - if ( - Option::get( $type . '_minify' ) - || Option::get( $type . '_combine' ) - || Option::get( $type . '_inline' ) - || Option::get( $type . '_disable' ) - || Option::get( $type . '_disable_position' ) - || Option::get( $type . '_minify_inline' ) - || Option::get( $type . '_defer' ) - ) { - return true; - } - - return false; - -} - - -/** - * Check if current page is plugin admin page - * - * @return boolean - * @since 1.0.3 - */ -function wpp_is_plugin_page() { - - if ( Input::get( 'page' ) == WPP_PLUGIN_ADMIN_URL ) { - return true; - } - - return false; - -} - - -/** - * Load admin template - * - * @param string $template - * @param array $vars - * @return string - * @since 1.0.6 - */ -function wpp_load_template( $template, $vars = [] ) { - - if ( file_exists( $file = WPP_ADMIN_DIR . $template . '.php' ) ) { - - ob_start(); - extract( $vars ); - include $file; - $content = ob_get_clean(); - - echo $content; - - } - -} \ No newline at end of file diff --git a/includes/functions/backend.php b/includes/functions/backend.php deleted file mode 100644 index 6cb4da1..0000000 --- a/includes/functions/backend.php +++ /dev/null @@ -1,298 +0,0 @@ - -* @package WPP -*/ - -use WPP\Cache; -use WPP\File; -use WPP\Input; -use WPP\Option; - -add_action( 'wpp_backend_init', function(){ - - // Clear cache from frontend ajax action - add_action( - 'wp_ajax_nopriv_wpp_clear_cache', - [ 'WPP\Cache', 'clear' ] - ); - - // Clear the cache after switching theme - add_action( - 'after_switch_theme', - function(){ - wpp_delete_list_options(); - Cache::clear(); - } - ); - - // Init admin - add_action( 'init', function() { - - // Check user - if ( ! current_user_can( 'manage_options' ) ) - return false; - - // Check if cache dir exists - if ( ! is_dir( WPP_CACHE_DIR ) ) { - if( ! mkdir( WPP_CACHE_DIR, 0755, true ) ) { - wpp_notify( sprintf( '%s: missing writing permissions for directory wp-content/cache', WPP_PLUGIN_NAME ), 'error', false ); - } else { - touch( WPP_CACHE_DIR . 'index.php' ); - } - } - - // Check if advanced-cache.php exists - if ( ! file_exists( trailingslashit( WP_CONTENT_DIR ) . 'advanced-cache.php' ) ) { - - wpp_notify( - sprintf( - __( 'File advanced-cache.php is missing. If you updated your installation of %s recently, try to deactivate and then activate the plugin again.', 'wpp' ), - WPP_PLUGIN_NAME - ), - 'error', - false - ); - - } - - // Get initial CSS and JS files by loading the front page - if ( ! Option::get( 'local_css' ) ) { - wpp_preload_homepage(); - } - - // Clear files list - if ( - Input::get( 'clear' ) - && wp_verify_nonce( Input::get( 'nonce' ), 'clear-list' ) - ) { - wpp_delete_files_list( Input::get( 'clear' ) ); - } - - // Enable disable plugin - if ( - Input::get( 'wpp-action' ) - && wp_verify_nonce( Input::get( 'wpp-nonce' ), 'temp-disable' ) - ) { - $status = ( Input::get( 'wpp-action' ) == 'disable' ) ? true : false; - Option::update( 'wpp_disable', $status ); - File::saveSiteSettings( [ 'disable' => $status ] ); - } - - // Save settings - if ( - Input::post( 'wpp-save-settings' ) - && wp_verify_nonce( Input::post( 'wpp-nonce' ), 'save-settings' ) - ) { - wpp_save_settings(); - } - - // Clear log file - if ( - Input::post( 'wpp-clear-log' ) - && wp_verify_nonce( Input::post( 'wpp-nonce' ), 'save-settings' ) - ) { - wpp_clear_log(); - } - - // Export settings - if ( - Input::get( 'wpp-export-settings' ) - && wp_verify_nonce( Input::get( 'wpp-nonce' ), 'export-settings' ) - ) { - wpp_export_settings_file(); - } - - // Import settings - if ( isset( $_FILES[ 'wpp_import_settings' ] ) ) { - wpp_import_settings( $_FILES ); - } - - - // Clear cache after post is added or updated - if ( Option::boolval( 'update_clear' ) ) { - add_action( - 'save_post', - [ 'WPP\Cache', 'clear' ], - 999 - ); - } - - // Clear cache after post is deleted - if ( Option::boolval( 'delete_clear' ) ) { - add_action( - 'delete_post', - [ 'WPP\Cache', 'clear' ], - 999 - ); - } - - // Save post options - add_action( - 'save_post', - 'wpp_save_post_options' - ); - - // Plugin compatibility check - add_action( - 'admin_init', - 'wpp_compatibility_check' - ); - - // Add top bar menu - add_action( - 'admin_init', - 'wpp_add_top_menu_item' - ); - - // Enqueue back-end scripts and styles - add_action( - 'admin_init', - 'wpp_enqueue_backend_assets' - ); - - // Initialize UI elements registered by add-ons - add_action( - 'admin_init', - [ 'WPP\UI', 'register' ] - ); - - // WPP admin page - add_action( - 'admin_menu', - 'wpp_add_menu_item' - ); - - // Filter image sizes - add_filter( - 'intermediate_image_sizes_advanced', - 'wpp_get_defined_image_sizes' - ); - - // Add page meta box - add_action( - 'add_meta_boxes', - 'wpp_add_metabox' - ); - - - } ); - - // Admin actions - add_action( 'admin_init', function() { - - // Clear cache ajax action - add_action( - 'wp_ajax_wpp_clear_cache', - [ 'WPP\Cache', 'clear' ] - ); - - // Clear database ajax actions - add_action( - 'wp_ajax_wpp_clean_database', - 'wpp_ajax_database_actions' - ); - - // Images ajax actions - add_action( - 'wp_ajax_wpp_images_action', - 'wpp_ajax_image_actions' - ); - - // Deactivate incompatible plugin - add_action( - 'admin_post_deactivate_plugin', - 'wpp_deactivate_incompatible_plugin' - ); - - // Get critical CSS ajax action - add_action( - 'wp_ajax_wpp_get_critical_css_path', - 'wpp_get_critical_css_path' - ); - - // Get log content - add_action( - 'wp_ajax_wpp_get_log_content', - 'wpp_ajax_get_log_content' - ); - - // Remove excluded page - add_action( - 'wp_ajax_wpp_remove_post_options', - 'wpp_ajax_remove_post_options' - ); - - // Add disable enable link - add_filter( - 'plugin_action_links_' . plugin_basename( WPP_SELF ), - 'wpp_add_disable_link' - ); - - add_filter( - 'plugin_row_meta', - 'wpp_add_plugin_extra_links', - 10, - 2 - ); - - // Check if plugin is disabled - if ( Option::boolval( 'wpp_disable' ) ) { - wpp_notify( - sprintf( '%s %s - %s', WPP_PLUGIN_NAME, __( 'is temporarily disabled', 'wpp' ), - '' . __( 'Enable', 'wpp' ) . ''), - 'warning', - false - ); - } - - // Check the size of log file - if ( - Option::boolval( 'enable_log' ) - && wpp_is_log_file_too_large() - ) { - wpp_notify( - sprintf( __( '%s: Log file is getting large, either clear the log or disable troubleshooting logging', 'wpp' ), WPP_PLUGIN_NAME ), - 'warning', - false - ); - } - - // Check if htaccess is writable and server is apache - if ( - wpp_get_server_software( 'apache' ) - && ! wpp_is_htaccess_writable() - ) { - wpp_notify( - sprintf( __( '%s: missing writing permissions for file .htaccess', 'wpp' ), WPP_PLUGIN_NAME ), - 'error', - false - ); - } - - // Check if Cloudflare api key and email are set - if ( - Option::boolval( 'cf_enabled' ) - && ! Option::boolval( 'cf_api_key' ) - && ! Option::boolval( 'cf_email' ) - ) { - wpp_notify( - sprintf( __( '%s: enter Cloudflare credentials', 'wpp' ), WPP_PLUGIN_NAME ), - 'warning', - false - ); - } - - // load settings file - if ( - Input::get( 'load' ) - && wp_verify_nonce( Input::get( 'nonce' ), 'load-config' ) - ) { - wpp_load_settings( Input::get( 'load' ) ); - } - - } ); - -} ); \ No newline at end of file diff --git a/includes/functions/cron.php b/includes/functions/cron.php deleted file mode 100644 index 0e6f1c4..0000000 --- a/includes/functions/cron.php +++ /dev/null @@ -1,252 +0,0 @@ - -* @package WPP -*/ - -use WPP\DB; -use WPP\File; -use WPP\Cache; -use WPP\Option; - -/** - * Get cron schedule intervals - * - * @param array $schedules - * @return array - * @since 1.0.0 - */ -function wpp_get_cron_schedules( $schedules = [] ) { - - - $schedules[ 'wpp_daily' ] = [ - 'interval' => strtotime( '+ 1 day') - time(), - 'display' => __( 'Daily', 'wpp' ) - ]; - - $schedules[ 'wpp_weekly' ] = [ - 'interval' => strtotime( '+ 1 week') - time(), - 'display' => __( 'Weekly', 'wpp' ) - ]; - - $schedules[ 'wpp_monthly' ] = [ - 'interval' => strtotime( '+ 1 month') - time(), - 'display' => __( 'Monthly', 'wpp' ) - ]; - - $schedules[ 'wpp_every_minute' ] = [ - 'interval' => 60, - 'display' => __( 'Every minute', 'wpp' ) - ]; - - $schedules[ 'wpp_every_5_minutes' ] = [ - 'interval' => 60 * 5, - 'display' => __( 'Every 5 minutes', 'wpp' ) - ]; - - return $schedules; - -} - -/** - * Preload cache - * - * @return void - * @since 1.0.0 - */ -function wpp_cron_preload_cache() { - - // Bail if preload file not exists - if ( ! file_exists( $file = WPP_CACHE_DIR . 'preload.json' ) ) { - return false; - } - - $data = File::getJson( $file ); - - if ( empty( $data ) ) { - wpp_log( 'Cache preloading stop - nothing to preload' ); - exit; - } - - wpp_log( 'Cache preloading start' ); - - $max_url = defined( 'WPP_PRELOAD_URL_NUMBER' ) ? WPP_PRELOAD_URL_NUMBER : 5; - - $i = 1; - - foreach( $data as $j => $url ) { - - // Check if cache file already exists - if ( Cache::exists( $url ) ) { - unset( $data[ $j ] ); - continue; - } - - $url = esc_url( $url ); - - $request = wp_remote_get( $url, [ - 'timeout' => 3 - ] ); - - if ( is_wp_error( $request ) ) { - wpp_log( sprintf( 'Error while trying to preload cache for page %s %s', $url, $request->get_error_message() ) ); - } - - unset( $data[ $j ] ); - - if ( $i == $max_url ) break; - - $i++; - - } - - File::saveJson( $file, $data ); - -} - - - -/** - * Prepare cache preload - * - * @return void - * @since 1.0.0 - */ -function wpp_cron_prepare_preload() { - - // Bail if preload file already exists - if ( file_exists( WPP_CACHE_DIR . 'preload.json' ) ) { - return false; - } - - $urls = []; - $sitemaps = Option::get( 'sitemaps_list', [] ); - - foreach( $sitemaps as $url ) { - - $url = esc_url( $url ); - - // Validate sitemap url - if ( ! filter_var( $url, FILTER_VALIDATE_URL ) ) { - - wpp_log( sprintf( 'Invalid sitemap url: %s', $url ) ); - - continue; - } - - - // Get the sitemap - $request = wp_remote_get( $url ); - - if ( is_wp_error( $request ) ) { - - wpp_log( sprintf( 'Error fetching sitemap url: %s %s', $url, $request->get_error_message() ) ); - - return false; - } - - $data = wp_remote_retrieve_body( $request ); - - if ( empty( $data ) ) { - - wpp_log( sprintf( 'Sitemap %s is empty', $url ) ); - - return false; - } - - // Load XML - libxml_use_internal_errors( true ); - - $xml = simplexml_load_string( $data ); - - if ( false === $xml ) { - - libxml_clear_errors(); - - wpp_log( sprintf( 'Invalid XML in sitemap %s', $url ) ); - - return false; - } - - - // Get urls - $num = count( $xml->url ); - - if ( $num > 0 ) { - for ( $i = 0; $i < $num; $i++ ) { - $urls[] = strval( $xml->url[ $i ]->loc ); - } - } - - } - - // Save file - if ( ! empty( $urls ) ) { - - File::saveJson( WPP_CACHE_DIR . 'preload.json', $urls ); - - wpp_log( sprintf( 'Collected %s URLs from %s sitemap(s) for cache preloading', count( $urls ), count( $sitemaps ) ) ); - - } else { - - wpp_log( 'URLs for cache preloading not found' ); - - } - - -} - - - -/** - * Clear DB and update next schedule info - * - * @return void - * @since 1.0.0 - */ -function wpp_cron_db_cleanup() { - - wpp_log( 'Automatic database cleanup started' ); - - // Clear trash - if ( Option::boolval( 'db_cleanup_trash' ) ) { - DB::clearTrash(); - } - - // Clear spam - if ( Option::boolval( 'db_cleanup_spam' ) ) { - DB::clearSpam(); - } - - // Clear revisions - if ( Option::boolval( 'db_cleanup_revisions' ) ) { - DB::clearRevisions(); - } - - // Clear revisions - if ( Option::boolval( 'db_cleanup_transients' ) ) { - DB::clearTransients(); - } - - // Clear cron tasks - if ( Option::boolval( 'db_cleanup_cron' ) ) { - DB::clearCronTasks(); - } - - // Clear auto drafts - if ( Option::boolval( 'db_cleanup_autodrafts' ) ) { - DB::clearAutoDrafts(); - } - - $schedules = wpp_get_cron_schedules(); - $frequency = Option::get( 'db_cleanup_frequency' ); - - if ( array_key_exists( $frequency, $schedules ) ) { - Option::update( 'db_cleanup_next', ( time() + $schedules[ $frequency ][ 'interval' ] ) ); - } else { - Option::remove( 'db_cleanup_next' ); - } - -} \ No newline at end of file diff --git a/includes/functions/db.php b/includes/functions/db.php deleted file mode 100644 index 2e1487b..0000000 --- a/includes/functions/db.php +++ /dev/null @@ -1,88 +0,0 @@ - -* @package WPP -*/ - - -use WPP\DB; -use WPP\Input; - - -/** - * Register database ajax actions - * - * @return json - * @since 1.0.0 - */ -function wpp_ajax_database_actions() { - - check_ajax_referer( 'wpp-ajax', 'nonce' ); - - switch( Input::post( 'db_action' ) ) { - - case 'revisions': - - DB::clearRevisions(); - wp_send_json( [ 'status' => 1 ] ); - - break; - - case 'spam': - - DB::clearSpam(); - wp_send_json(['status' => 1]); - - break; - - case 'trash': - - DB::clearTrash(); - wp_send_json(['status' => 1]); - - break; - - case 'transients': - - DB::clearTransients(); - wp_send_json(['status' => 1]); - - break; - - case 'cron': - - DB::clearCronTasks(); - wp_send_json(['status' => 1]); - - break; - - case 'drafts': - - DB::clearAutoDrafts(); - wp_send_json(['status' => 1]); - - break; - - case 'all': - - DB::clearRevisions(); - DB::clearSpam(); - DB::clearTrash(); - DB::clearTransients(); - DB::clearCronTasks(); - DB::clearAutoDrafts(); - - wp_send_json(['status' => 1]); - - break; - - } - - wp_send_json( [ - 'status' => 0, - 'note' => __( 'You are doing it wrong', 'wpp' ) - ] ); - -} \ No newline at end of file diff --git a/includes/functions/ecommerce.php b/includes/functions/ecommerce.php deleted file mode 100644 index 8681c20..0000000 --- a/includes/functions/ecommerce.php +++ /dev/null @@ -1,66 +0,0 @@ - -* @package WPP -*/ - -use WPP\Url; - -/** - * Exclude WooCommerce pages - * - * @param array $exclude - * @return array - * @since 1.0.0 - */ -function wpp_exclude_woocommerce_pages( $exclude ) { - - // Check if woocommerce class exists - if ( class_exists( 'WooCommerce' ) ) { - if ( - is_checkout() - || is_account_page() - || is_cart() - ) { - array_push( $exclude, Url::current() ); - } - } - - return $exclude; - -} - -// Exclude WooCommerce pages -add_filter( 'wpp_exclude_urls', 'wpp_exclude_woocommerce_pages' ); - -/** - * Exclude EDD pages checkout, account and cart - * - * @param array $exclude - * @return array - * @since 1.0.0 - */ -function wpp_exclude_edd_pages( $exclude ) { - - if ( class_exists( 'Easy_Digital_Downloads' )) { - - if ( - edd_is_checkout() - || edd_is_success_page() - || edd_is_failed_transaction_page() - || edd_is_purchase_history_page() - || edd_is_test_mode() - ) { - array_push( $exclude, Url::current() ); - } - - } - - return $exclude; - -} - -// Exclude EDD pages -add_filter( 'wpp_exclude_urls', 'wpp_exclude_edd_pages' ); \ No newline at end of file diff --git a/includes/functions/exclude.php b/includes/functions/exclude.php deleted file mode 100644 index 07ba66b..0000000 --- a/includes/functions/exclude.php +++ /dev/null @@ -1,49 +0,0 @@ - -* @package WPP -*/ - -use WPP\Option; - -/** - * Exclude manually added pages from - * Cache - * CSS optimization - * JavaScript optimization - * Image optimization - * Iframe lazyload - * - * @param array $exclude - * @return array - * @since 1.0.3 - */ -add_action( 'init', function() { - - $hooks = [ - 'wpp_css_url_exclude' => 'css_post_exclude', - 'wpp_js_url_exclude' => 'js_post_exclude', - 'wpp_exclude_urls' => 'cache_post_exclude', - 'wpp_image_url_exclude' => 'image_url_exclude', - 'wpp_video_url_exclude' => 'video_url_exclude', - ]; - - foreach( $hooks as $filter => $option ) { - - add_filter( $filter, function( $exclude ) use( $option ) { - - $pages = Option::get( $option, [] ); - - foreach ( $pages as $id ) { - $exclude[] = get_permalink( $id ); - } - - return $exclude; - - } ); - - } - -} ); \ No newline at end of file diff --git a/includes/functions/files.php b/includes/functions/files.php deleted file mode 100644 index 26d7726..0000000 --- a/includes/functions/files.php +++ /dev/null @@ -1,389 +0,0 @@ - -* @package WPP -*/ - -use WPP\File; -use WPP\Option; - -/** - * Get clean file name - * - * @since 1.0.0 - * @return string - */ -function wpp_get_file_clean_name( $file ) { - return sanitize_title( urldecode( $file ) ); -} - - -/** - * Get cache size for given file type extension - * - * @since 1.0.0 - * @param string $type - * @return int - */ -function wpp_cache_files_size( $type ) { - - $size = 0; - - $cache_dir = WPP_CACHE_DIR; - - if ( is_multisite() ) { - $uri = parse_url( get_bloginfo( 'url' ) ); - $cache_dir = WPP_CACHE_DIR . $uri[ 'host' ] . $uri[ 'path' ]; - } - - if ( ! is_dir( $cache_dir ) ) - return $size; - - $files = new \RecursiveIteratorIterator( - new \RecursiveDirectoryIterator( $cache_dir, \RecursiveDirectoryIterator::SKIP_DOTS ), - \RecursiveIteratorIterator::CHILD_FIRST - ); - - foreach ( $files as $file ) { - - if ( $file->isFile() ) { - - if ( $file->getExtension() == $type ) { - $size += $file->getSize(); - } - - } - } - - return $size; - -} - - -/** - * Get human readable file size - * - * @since 1.0.0 - * @param integer $bytes - * @param integer $decimals - * @return string - */ -function wpp_filesize( $bytes, $decimals = 2 ) { - - $size = array( 'B', 'KB', 'MB', 'GB', 'TB' ); - $factor = floor( ( strlen( $bytes ) - 1 ) / 3 ); - - return sprintf( "%.{$decimals}f", $bytes / pow( 1024, $factor ) ) . @$size[ $factor ]; -} - - -/** - * Guess if file is minified - * - * This function will try to guess if file is already minified by checking the file name - * Most of the time minified files have .min.* extension, so we check for that in file name - * Also the function will return true for every file located in wp-includes directory - * - * @since 1.0.0 - * @param string $file - * @return boolean - */ -function wpp_is_minified( $file ) { - - if ( strstr( $file, '.min.' ) || strstr( $file, 'wp-includes/' ) ) { - return true; - } - - return false; - -} - - -/** - * Check if htaccess file is writable - * - * @return boolean - * @since 1.0.0 - */ -function wpp_is_htaccess_writable() { - return is_writable( trailingslashit( ABSPATH ) . '.htaccess' ); -} - - -/** - * Add remove definitions from htaccess file - * - * @since 1.0.0 - * @param string $action - * @param string $file - * @return void - */ -function wpp_update_htaccess( $action, $file ) { - - $htaccess = trailingslashit( ABSPATH ) . '.htaccess'; - $definitionsFile = WPP_DATA_DIR . 'definitions/' . $file . '.apache.txt'; - $customDefinitionsFile = WPP_DATA_DIR . 'definitions/' . 'custom.' . $file . '.apache.txt'; - - // Use custom definitions if exists - if ( file_exists( $customDefinitionsFile ) ) { - $definitionsFile = $customDefinitionsFile; - } - - if ( ! file_exists( $definitionsFile ) ) { - - wpp_log( sprintf( '%s not exists', $definitionsFile ) ); - - return false; - } - - $htaccess_content = File::get( $htaccess ); - $definitions_content = File::get( $definitionsFile ); - - switch ( $action ) { - - case 1: - case 'add': - - if ( ! file_exists( $htaccess ) ) { - - touch( $htaccess ); - - } else { - - if ( ! wpp_is_htaccess_writable() ) { - - wpp_log( '.htaccess file not writable' ); - - return false; - } - - } - - - switch( $file ) { - - case 'cache': - - $definitions_content = str_replace( '{BASEDIR}', wpp_get_basedir(), $definitions_content ); - $definitions_content = str_replace( '{CONTENT_DIR}', basename( WP_CONTENT_DIR ), $definitions_content ); - - // Get excluded user agents - $agents = Option::get( 'user_agents_exclude', [] ); - - // Check if exclude search engines option is on - if ( Option::boolval( 'search_bots_exclude' ) ) { - $agents = array_merge( $agents, wpp_get_search_engines() ); - } - - - if ( ! empty( $agents ) ) { - - $agents = array_map( function( $agent ) { - - $agent = trim( $agent ); - - // If user agent is empty we should return something to prevent 500 error - if ( empty( $agent ) ) { - return 'WPP'; - } - - return preg_quote( $agent ); - - }, $agents ); - - $condition = 'RewriteCond %{HTTP_USER_AGENT} !(' . implode( '|', $agents ) . ') [NC]'; - - } else { - $condition = ''; - } - - $definitions_content = str_replace( '{USER_AGENTS}', $condition, $definitions_content ); - $definitions_content = str_replace( '{AMP_TAG}', wpp_get_constant( 'WPP_AMP_TAG', 'amp' ), $definitions_content ); - - if ( ! preg_match( '/# WPP Cache load start(.*?)# WPP Cache load end/s', $htaccess_content ) ) { - File::prepend( $htaccess, $definitions_content ); - } - - break; - - case 'gzip': - - if ( ! preg_match( '/# WPP GZIP start(.*?)# WPP GZIP end/s', $htaccess_content ) ) { - File::append( $htaccess, $definitions_content ); - } - - break; - - case 'expire': - - if ( ! preg_match( '/# WPP Expire start(.*?)# WPP Expire end/s', $htaccess_content ) ) { - File::append( $htaccess, $definitions_content ); - } - - break; - } - - - - break; - - case 0: - case 'remove': - - if ( file_exists( $htaccess ) ) { - - switch( $file ) { - - case 'cache': - - if ( preg_match( '/# WPP Cache load start(.*?)# WPP Cache load end/s', $htaccess_content, $match ) ) { - $content = str_replace( PHP_EOL . $match[ 0 ] . PHP_EOL, '', $htaccess_content ); - File::save( $htaccess, $content ); - } - - break; - - case 'gzip': - - if ( preg_match( '/# WPP GZIP start(.*?)# WPP GZIP end/s', $htaccess_content, $match ) ) { - $content = str_replace( PHP_EOL . $match[ 0 ] . PHP_EOL, '', $htaccess_content ); - File::save( $htaccess, $content ); - } - - break; - - case 'expire': - - if ( preg_match( '/# WPP Expire start(.*?)# WPP Expire end/s', $htaccess_content, $match ) ) { - $content = str_replace( PHP_EOL . $match[ 0 ] . PHP_EOL, '', $htaccess_content ); - File::save( $htaccess, $content ); - } - - break; - } - - } - - break; - } - -} - - -/** - * Get site base directory - * - * @return string - * @since 1.0.0 - */ -function wpp_get_basedir() { - - $root_dir = basename( WPP\Input::server( 'DOCUMENT_ROOT' ) ); - $base_dir = basename( ABSPATH ); - - if ( $root_dir != $base_dir ) { - return sprintf( '/%s/', $base_dir ); - } - - return '/'; - -} - - -/** - * Get site log file path - * - * @return void - * @since 1.0.0 - */ -function wpp_get_log_file() { - - if ( is_multisite() ) - return WPP_CACHE_DIR . get_current_blog_id() . '_wpp.log'; - - return WPP_CACHE_DIR . 'wpp.log'; -} - -/** - * Write log - * - * @param string $action - * @return void - * @since 1.0.0 - */ -function wpp_log( $action ) { - - if ( ! Option::boolval( 'enable_log' ) ) return; - - File::append( wpp_get_log_file(), sprintf( - '[%s] %s', - date( 'Y-m-d H:i:s' ), - $action . PHP_EOL - ) ); - -} - - - -/** - * Clear the log file - * - * @return void - * @since 1.0.0 - */ -function wpp_clear_log() { - - if ( file_exists( $file = wpp_get_log_file() ) ) { - unlink( $file ); - } - - wpp_notify( 'Log file cleared' ); - -} - - -/** - * Get log content via ajax - * - * @return void - * @since 1.0.0 - */ -function wpp_ajax_get_log_content() { - - check_ajax_referer( 'wpp-ajax', 'nonce' ); - - if ( file_exists( $file = wpp_get_log_file() ) ) { - echo File::get( $file ); - } - - exit; - -} - - - -/** - * Check if log file is too large - * - * @return void - * @since 1.0.0 - */ -function wpp_is_log_file_too_large() { - - /** - * Set log size filter - * @since 1.0.0 - */ - $log_size = apply_filters( 'wpp-log-size-kb', 20 ); - - if ( file_exists( $log_file = wpp_get_log_file() ) ) { - if ( filesize( $log_file ) > ( intval( $log_size ) * 1024 ) ) { - return true; - } - } - - return false; - -} \ No newline at end of file diff --git a/includes/functions/frontend.php b/includes/functions/frontend.php deleted file mode 100644 index 48da6d8..0000000 --- a/includes/functions/frontend.php +++ /dev/null @@ -1,92 +0,0 @@ - - * @package WPP - */ - -use WPP\Url; -use WPP\Cache; -use WPP\Option; - -add_action( 'wpp_frontend_init', function() { - - add_action( 'init', function() { - // Check if user is logged in - if ( is_user_logged_in() && current_user_can( 'manage_options' ) ) - wpp_add_top_menu_item(); - }); - - // Disable emoji - if ( Option::boolval( 'disable_emoji' ) ) - add_action( 'init', 'wpp_disable_emoji' ); - - // Disable embeds - if ( Option::boolval( 'disable_embeds' ) ) - add_action( 'init', 'wpp_disable_embeds', 99999 ); - - // Hook up - add_action( 'wp', function() { - // Do not parse template if it's an ajax request - if ( ! wpp_is_ajax() ) - is_404() || ob_start( [ 'WPP\Parser', 'init' ] ); - } ); - - // Referesh page cache on POST request - if ( ! empty( $_POST ) ) { - - if ( file_exists( $page = Cache::getFileName() ) ) { - - unlink( $page ); - - foreach( [ '_gz', '_amp' ] as $extension ) { - if ( file_exists( $page . $extension ) ) - unlink( $page . $extension ); - } - - } - - } - -} ); - - -// Save cache file -add_filter( 'wpp_template', function( $template, $is_amp, $time ) { - - // Should we cache this page ? - if ( - Option::boolval( 'cache' ) - && empty( $_POST ) - && ! is_user_logged_in() - ) { - - /** - * Filter excluded urls - * - * @since 1.0.0 - */ - $excluded = apply_filters( 'wpp_exclude_urls', Option::get( 'cache_url_exclude', [] ) ); - - // Check if page is excluded - if ( ! wpp_is_url_excluded( Url::current(), $excluded ) ) { - - if ( ! $is_amp ) { - - $template .= sprintf( - '', - number_format( ( microtime( true ) - $time ), 2 ), - date( get_option( 'date_format' ) ), - date( get_option( 'time_format' ) ) - ); - - } - - Cache::save( $template, $is_amp ); - - } - - } - -}, 10, 3); \ No newline at end of file diff --git a/includes/functions/image.php b/includes/functions/image.php deleted file mode 100644 index 02f3eb0..0000000 --- a/includes/functions/image.php +++ /dev/null @@ -1,211 +0,0 @@ - -* @package WPP -*/ - -use WPP\Input; -use WPP\Image; -use WPP\Option; - - -/** - * Get defined image sizes - * - * @param array $sizes - * @return void - * @since 1.0.0 - */ -function wpp_get_defined_image_sizes( $sizes ) { - - $sizes = []; - - $custom_sizes = Image::getAllDefinedSizes(); - - foreach( $custom_sizes as $name => $size ) { - - $sizes[ $name ] = [ - 'width' => $size[ 0 ], - 'height' => $size[ 1 ], - 'crop' => isset( $size[ 2 ] ) ? $size[ 2 ] : '' - ]; - - } - - return $sizes; - -} - - -/** - * Register image ajax actions - * - * @return void - * @since 1.0.3 - */ -function wpp_ajax_image_actions() { - - check_ajax_referer( 'wpp-ajax', 'nonce' ); - - switch ( Input::post( 'image_action' ) ) { - - case 'add_size': - - // get all sizes - $all_sizes = Image::getAllDefinedSizes(); - - parse_str( Input::post( 'size' ), $size ); - - // check size name - if ( array_key_exists( $size[ 'name' ], $all_sizes ) ) { - - wpp_log( sprintf( 'Image size %s already in use', $size[ 'name' ] ) ); - - wp_send_json( [ - 'status' => 0, - 'error' => __( 'Size name already in use', 'wpp' ) - ] ); - - } - - $sizes = Option::get( 'image_sizes', [] ); - - $sizes = array_merge( $sizes, [ - $size[ 'name' ] => [ - intval( $size[ 'width' ] ), - intval( $size[ 'height' ] ), - isset( $size[ 'crop' ] ) ? 1 : '' - ] - ]); - - if ( Option::update( 'image_sizes', $sizes ) ) { - - wpp_log( sprintf( 'Image size %s added', $size[ 'name' ] ) ); - - wp_send_json( [ 'status' => 1 ] ); - } - - break; - - case 'remove_size': - - $name = Input::post( 'size' ); - - // Image sizes defined from WPP - $wpp_sizes = Option::get( 'image_sizes', [] ); - - if ( array_key_exists( $name, $wpp_sizes ) ) { - - unset( $wpp_sizes[ $name ] ); - - if ( Option::update( 'image_sizes', $wpp_sizes ) ) { - - wpp_log( sprintf( 'Image size %s removed', $name ) ); - - wp_send_json( [ 'status' => 1 ] ); - } - - } - - // The rest of image sizes - if ( array_key_exists( $name, Image::sizes() ) ) { - - $removed_sizes = Option::get( 'image_sizes_remove', [] ); - - if ( ! in_array( $name, $removed_sizes ) ) { - - array_push( $removed_sizes, $name ); - - if ( Option::update( 'image_sizes_remove', $removed_sizes ) ) { - - wpp_log( sprintf( 'Image size %s removed', $name ) ); - - wp_send_json( [ 'status' => 1 ] ); - } - - } - - } - - break; - - case 'restore_sizes': - - Option::update( 'image_sizes', [] ); - Option::update( 'image_sizes_remove', [] ); - - wpp_log( 'Image sizes restored' ); - - wp_send_json( [ 'status' => 1 ] ); - - - break; - - case 'get_all_sizes': - - wp_send_json( [ 'sizes' => Image::getAllDefinedSizesJson( false ) ] ); - - break; - - case 'regenerate_thumbnails': - - if ( Input::post( 'remove_flag' ) === 'true' ) { - delete_post_meta_by_key( 'wpp_thumb_regenerated' ); - wpp_log( 'Thumb regeneration start' ); - } - - if ( $image = Image::getNonRegenerated( 1 ) ) { - - if ( $file = get_attached_file( $image[ 0 ]->ID ) ) { - - $info = pathinfo( $file ); - - // Delete old thumbs - foreach( glob( $info[ 'dirname' ] . DIRECTORY_SEPARATOR . $info[ 'filename' ] . '-*.' . $info[ 'extension' ] ) as $thumb ) { - unlink( $thumb ); - } - - $meta = wp_generate_attachment_metadata( $image[ 0 ]->ID, $file ); - - wp_update_attachment_metadata( $image[ 0 ]->ID, $meta ); - - add_post_meta( $image[ 0 ]->ID, 'wpp_thumb_regenerated', true ); - - } - - $total = count( Image::getAllImages() ); - $pending = count( Image::getNonRegenerated() ); - $percent = ( $total - $pending != 0 ) ? ( ( $total - $pending ) / $total ) * 100 : 0; - - $filename = str_replace( wp_normalize_path( ABSPATH ), '', wp_normalize_path( $file ) ); - - wpp_log( sprintf( 'Thumbs regenerated for %s', $filename ) ); - - wp_send_json( [ - 'process' => true, - 'pending' => $pending, - 'total' => $total, - 'info' => sprintf( _n( '%s image left', '%s images left', $pending, 'wpp' ), $pending ), - 'percent' => number_format( $percent, 2 ) - ] ); - - } else { - - wpp_log( 'Thumb regeneration end' ); - - wp_send_json( [ - 'process' => false, - 'pending' => 0, - 'total' => 0, - 'info' => __( 'Done', 'wpp' ), - 'percent' => 100 - ] ); - - } - - break; - - } -} diff --git a/includes/functions/index.html b/includes/functions/index.html deleted file mode 100644 index e69de29..0000000 diff --git a/includes/functions/miscellaneous.php b/includes/functions/miscellaneous.php deleted file mode 100644 index ba573ae..0000000 --- a/includes/functions/miscellaneous.php +++ /dev/null @@ -1,544 +0,0 @@ - -* @package WPP -*/ - -use WPP\Url; -use WPP\File; -use WPP\Cache; -use WPP\Input; -use WPP\Option; - -/** - * Check if array key exists - * - * @since 1.0.0 - * @param string $key - * @param array $array - * @param mixed $array_key - * - * @return bool - */ -function wpp_key_exists( $key, $array, $array_key = null ) { - - if ( ! $key ) return false; - - if ( ! is_null( $array_key ) ) { - - if ( isset( $array[ $array_key ] ) ) { - return in_array( $key, array( $array[ $array_key ] ) ); - } - - return false; - - } - if ( is_array( $array ) ) { - return array_key_exists( $key, $array ); - } - - return false; -} - -/** -* Check if key or array of keys exists in array or string -* -* @since 1.0.0 -* @param mixed $needle -* @param mixed $haystack -* -* @return bool -*/ -function wpp_in_array( $needle, $haystack ) { - - if ( is_array( $needle ) ) { - - foreach( $needle as $_needle ) { - - if ( empty( $_needle ) ) continue; - - if ( is_array( $haystack ) ) { - - foreach( $haystack as $_haystack ) { - if ( stristr( $_haystack, $_needle ) ) { - return true; - } - } - - } - - if ( stristr( $haystack, $_needle ) ) { - return true; - } - - } - - return false; - } - - if ( is_array( $haystack ) ) { - - foreach ( $haystack as $_haystack ) { - if ( stristr( $_haystack, $needle ) ) { - return true; - } - } - - return false; - } - - if ( empty( $needle ) ) return false; - - return stristr( $haystack, $needle ); - -} - - -/** - * Preload home page - * - * @return void - * @since 1.0.0 - */ -function wpp_preload_homepage() { - - $request = wp_remote_get( site_url(), [ - 'timeout' => 5 - ] ); - - if ( is_wp_error( $request ) ) { - wpp_log( sprintf( 'Error while trying to preload cache for home page %s', $request->get_error_message() ) ); - } - -} - - -/** - * Cleanup site header - * - * @since 1.0.0 - * @return void - */ -function wpp_cleanup_header() { - - remove_action( 'wp_head', 'wp_generator' ); - remove_action( 'wp_head', 'wlwmanifest_link' ); - remove_action( 'wp_head', 'rsd_link' ); - remove_action( 'wp_head', 'wp_shortlink_wp_head' ); - remove_action( 'wp_head', 'adjacent_posts_rel_link_wp_head', 10 ); - - add_filter( 'the_generator', '__return_false' ); - -} - - -/** - * Disable Emoji - * - * @since 1.1.6 - * @return void - */ -function wpp_disable_emoji() { - remove_action( 'wp_head', 'print_emoji_detection_script', 7 ); - remove_action( 'admin_print_scripts', 'print_emoji_detection_script' ); - remove_action( 'wp_print_styles', 'print_emoji_styles' ); - remove_action( 'admin_print_styles', 'print_emoji_styles' ); - remove_filter( 'the_content_feed', 'wp_staticize_emoji' ); - remove_filter( 'comment_text_rss', 'wp_staticize_emoji' ); - remove_filter( 'wp_mail', 'wp_staticize_emoji_for_email' ); - add_filter( 'tiny_mce_plugins', 'wpp_disable_emojis_tinymce' ); - add_filter( 'wp_resource_hints', 'wpp_disable_emojis_remove_dns_prefetch', 10, 2 ); -} - -/** - * Remove the tinymce emoji plugin - * - * @since 1.1.6 - * @param array $plugins - * @return array - */ -function wpp_disable_emojis_tinymce( $plugins ) { - - if ( is_array( $plugins ) ) - return array_diff( $plugins, [ 'wpemoji' ] ); - - return []; -} - -/** -* Remove emoji CDN hostname from DNS prefetching hints - -* @since 1.1.6 -* @param array $urls -* @param string $relation -* @return array -*/ -function wpp_disable_emojis_remove_dns_prefetch( $urls, $relation ) { - - if ( 'dns-prefetch' == $relation ) { - $url = apply_filters( 'emoji_svg_url', 'https://s.w.org/images/core/emoji/2/svg/' ); - $urls = array_diff( $urls, [ $url ] ); - } - - return $urls; -} - - -/** - * Disable WP embeds - * - * @since 1.1.6 - * @return void - */ -function wpp_disable_embeds() { - - remove_action( 'rest_api_init', 'wp_oembed_register_route' ); - remove_action( 'wp_head', 'wp_oembed_add_discovery_links' ); - remove_action( 'wp_head', 'wp_oembed_add_host_js' ); - - remove_filter( 'oembed_dataparse', 'wp_filter_oembed_result', 10 ); - remove_filter( 'pre_oembed_result', 'wp_filter_pre_oembed_result', 10 ); - - add_filter( 'embed_oembed_discover', '__return_false' ); - add_filter( 'tiny_mce_plugins', 'wpp_disable_embeds_tinymce_plugin' ); - add_filter( 'rewrite_rules_array', 'wpp_disable_embeds_rewrites' ); - -} - -/** - * Remove the tinymce embed plugin - * - * @since 1.1.6 - * @param array $plugins - * @return array - */ -function wpp_disable_embeds_tinymce_plugin( $plugins ) { - return array_diff( $plugins, [ 'wpembed' ] ); -} - -/** - * Disable embed rewrite rules - * - * @since 1.1.6 - * @param array $rules - * @return array - */ -function wpp_disable_embeds_rewrites( $rules ) { - - foreach ( $rules as $rule => $rewrite ) { - if (false !== strpos( $rewrite, 'embed=true' ) ) - unset( $rules[ $rule ] ); - } - - return $rules; -} - - -/** - * Enqueue back-end scripts and styles - * - * @return void - * @since 1.0.0 - */ -function wpp_enqueue_backend_assets() { - - // Enqueue scripts and styles - wp_enqueue_script( 'wpp-confirms', WPP_ASSET_URL . 'confirm.js', [ 'jquery' ], WPP_VERSION ); - wp_enqueue_script( 'wpp-settings', WPP_ASSET_URL . 'admin.js', [ 'jquery', 'jquery-ui-autocomplete' ], WPP_VERSION ); - - wp_localize_script( 'wpp-settings', 'WPP', [ - 'path' => WPP_ASSET_URL, - 'site_url' => trailingslashit( site_url() ), - 'admin_url' => trailingslashit( admin_url() ), - 'nonce' => wp_create_nonce( 'wpp-ajax' ), - 'lang' => [ - 'confirm' => __( 'Are you sure?', 'wpp' ), - 'remove' => __( 'Remove', 'wpp' ), - 'yes' => __( 'Yes', 'wpp' ), - 'add_url' => __( 'Add URL', 'wpp' ), - 'disable_everywhere' => __( 'Disable everywhere', 'wpp' ), - 'disable_selected_url' => __( 'Disable only on selected URL', 'wpp' ), - 'disable_everywhere_except' => __( 'Disable everywhere except on selected URL', 'wpp' ), - 'something_went_wrong' => __( 'Something went wrong', 'wpp' ), - 'regenerate_thumbs' => __( 'Regenerating thumbs', 'wpp' ), - 'regenerate_thumbs_info' => __( 'Regenerate thumbnails may take a long time. Do not close your browser.', 'wpp' ), - ], - 'autocomplete' => [ - 'css' => array_merge( - Option::get( 'theme_css_list', [] ), - Option::get( 'plugin_css_list', [] ) - ), - 'js' => array_merge( - Option::get( 'theme_js_list', [] ), - Option::get( 'plugin_js_list', [] ) - ) - ] - ] ); - - wp_enqueue_style( 'wpp-admin-css', WPP_ASSET_URL . 'style.css', [], WPP_VERSION ); - wp_enqueue_style( 'wpp-overlay', WPP_ASSET_URL . 'overlay.css', [], WPP_VERSION ); - wp_enqueue_style( 'wpp-confirm', WPP_ASSET_URL . 'confirm.css', [], WPP_VERSION ); - -} - - -/** - * Check if css/js optimization is disabled for logged in users - * - * @param string $type - * @return boolean - * @since 1.0.0 - */ -function wpp_is_optimization_disabled_for( $type ) { - - if ( ! in_array( $type, [ 'js', 'css' ] ) ) { - return false; - } - - if ( Option::boolval( $type . '_disable_loggedin' ) ) { - if ( is_user_logged_in() ) return true; - } - - return false; - -} - - -/** - * Check if resource is disabled for current url - * - * @since 1.0.0 - * @return bool - */ -function wpp_is_resource_disabled( $type, $resource ) { - - if ( ! in_array( $type, [ 'js', 'css' ] ) ) { - return false; - } - - $disabled_positions = Option::get( $type . '_disable_position', [] ); - - // File is disabled everywhere - if ( wpp_key_exists( 'everywhere', $disabled_positions, $resource ) ) { - return true; - } - - - // File is disabled only for selected urls - if ( wpp_key_exists( 'selected', $disabled_positions, $resource ) ) { - - foreach( Option::get( $type . '_disable_selected', [] ) as $file => $urls ) { - - if ( $file == $resource ) { - - foreach( $urls as $url ) { - - $url = trailingslashit( wpp_url_replace_wildcards( $url ) ); - - // Try simple match first - if ( $url == Url::current() ) { - return true; - } - - /* - if ( stristr( Url::current(), $url ) ) { - return true; - } - */ - - preg_match( '#^' . $url . '$#', Url::current(), $match ); - - if ( isset( $match[0] ) ) { - return true; - } - - } - - } - - } - - return false; - - } - - // File is disabled everywhere except for current URL - if ( wpp_key_exists( 'except', $disabled_positions, $resource ) ) { - - $found = false; - - foreach( Option::get( $type . '_disable_except', [] ) as $file => $urls ) { - - if ( $file == $resource ) { - - $found = true; - - foreach( $urls as $url ) { - - $url = trailingslashit( wpp_url_replace_wildcards( $url ) ); - - // Try simple match first - if ( $url == Url::current() ) { - return false; - } - - /* - if ( stristr( Url::current(), $url ) ) { - return false; - } - */ - - preg_match( '#^' . $url . '$#', trailingslashit( Url::current() ), $match ); - - if ( isset( $match[0] ) ) { - return false; - } - - } - - } - - } - - // If file is found on page - if ( $found ) { - return true; - } - - } - - return false; - -} - - -/** - * Get critical CSS path from wpp server - * - * @since 1.0.0 - * @return array - */ -function wpp_get_critical_css_path() { - - /** - * Check nonce - * @since 1.0.6 - */ - check_ajax_referer( 'wpp-ajax', 'nonce' ); - - // Disable plugin - Option::update( 'wpp_disable', true ); - File::saveSiteSettings( [ 'disable' => true ] ); - - // Clear the cache - Cache::clear( false ); - - $response = wp_remote_post( - 'https://www.wp-performance.com/api', [ - 'timeout' => 90, - 'body' => [ - 'url' => site_url() - ] - ] - ); - - if ( is_wp_error( $response ) ) { - - $json = [ - 'status' => 0, - 'message' => $response->get_error_message() - ]; - - wpp_log( sprintf( 'Generating critical CSS error %s', $response->get_error_message() ) ); - - } else { - - $json = [ - 'status' => 1, - 'data' => wp_remote_retrieve_body( $response ) - ]; - - wpp_log( 'Critical CSS generated' ); - - } - - // Re-enable the plugin - Option::update( 'wpp_disable', false ); - File::saveSiteSettings( [ 'disable' => false ] ); - - wp_send_json( $json ); - -} - - -/** - * Get search engines list - * - * @return array - * @since 1.1.0 - */ -function wpp_get_search_engines() { - - return [ - 'Googlebot', - 'Bingbot', - 'Slurp', - 'DuckDuckBot', - 'Baiduspider', - 'YandexBot', - 'Sogou', - 'Exabot', - 'facebookexternalhit', - 'facebot', - 'ia_archiver' - ]; - -} - -/** - * Get constant value if constant is defined, otherwise return fallback - * - * @param string $constant - * @param mixed $fallback - * @return mixed - * @since 1.1.4 - */ -function wpp_get_constant( $constant, $fallback = false ) { - - return defined( $constant ) - ? constant( $constant ) - : $fallback; - -} - -/** - * Check if it's an ajax request - * @since 1.1.6 - * - * @return bool - */ -function wpp_is_ajax() { - - if( - Input::server( 'HTTP_X_REQUESTED_WITH' ) - && strtolower( Input::server( 'HTTP_X_REQUESTED_WITH' ) ) == 'xmlhttprequest' - || ( function_exists( 'wp_doing_ajax' ) && wp_doing_ajax() ) - ) { - return true; - } - - return false; - -} - -function wpp_add_plugin_extra_links( $links, $file ) { - - if ( strpos( $file, basename( WPP_SELF ) ) ) { - $links[] = 'Buy me a coffee ☕'; - } - - return $links; -} - \ No newline at end of file diff --git a/includes/functions/plugin.php b/includes/functions/plugin.php deleted file mode 100644 index 99eb1d2..0000000 --- a/includes/functions/plugin.php +++ /dev/null @@ -1,329 +0,0 @@ - -* @package WPP -*/ - -use WPP\Cache; -use WPP\Input; -use WPP\Option; - -/** - * WPP activate - * - * @return void - * @since 1.0.0 - */ -function wpp_activate() { - - // Define WP_CACHE - wpp_define_wp_cache(); - - // Copy advanced-cache.php file - if ( ! copy( - WPP_DIR . 'includes/advanced-cache.php', - trailingslashit( WP_CONTENT_DIR ) . 'advanced-cache.php' - ) ) { - wpp_log( sprintf( 'Error: cannot copy advanced-cache.php to %s directory. Check writing permissions', WP_CONTENT_DIR ) ); - } - - if ( 'apache' !== wpp_get_server_software() ) return; - - $backup = trailingslashit( ABSPATH ) . '.htaccess_wpp_backup'; - $htaccess = trailingslashit( ABSPATH ) . '.htaccess'; - - // Backup htaccess file - if ( file_exists( $htaccess ) ) { - - if( ! file_exists( $backup ) ) { - // Create htaccess backup - if ( copy( $htaccess, $backup ) ) - wpp_log( '.htaccess backup created' ); - - } - - } else { - // Create htaccess file if it doesn't exist - if ( ! touch( $htaccess ) ) - wpp_log( 'Error while trying to create .htaccess file. You will need to create it manually' ); - - } - -} - - -/** - * WPP deactivate - * - * @return void - * @since 1.0.0 - */ -function wpp_deactivate() { - - $backup = trailingslashit( ABSPATH ) . '.htaccess_wpp_backup'; - $htaccess = trailingslashit( ABSPATH ) . '.htaccess'; - - // Don't remove advanced-cache.php on multisite - if ( ! is_multisite() ) { - - // Delete advanced-cache.php file - if ( file_exists( $advanced_cache = trailingslashit( WP_CONTENT_DIR ) . 'advanced-cache.php' ) ) - unlink( $advanced_cache ); - - // Remove WP_CACHE constant - wpp_define_wp_cache( false ); - - } - - // Restore htaccess backup - if ( file_exists( $backup ) ) { - - if ( file_exists( $htaccess ) ) { - copy( $backup, $htaccess ); - wpp_log( '.htaccess backup restored' ); - } - - unlink( $backup ); - - } else { - - // .htaccess may not be present when WP performance is activated and thats why there is no htaccess backup - // lets do additional check if htaccess file exists so we can clean it up - if ( file_exists( $htaccess ) ) { - - // Browser cache - wpp_update_htaccess( 'remove', 'expire' ); - // Gzip compression - wpp_update_htaccess( 'remove', 'gzip' ); - // Htaccess load cache - wpp_update_htaccess( 'remove', 'cache' ); - - } - - } - - // Clear cron tasks - wp_clear_scheduled_hook( 'wpp_prepare_preload' ); - wp_clear_scheduled_hook( 'wpp_preload_cache' ); - wp_clear_scheduled_hook( 'wpp_db_cleanup' ); - - // Clear the cache - Cache::clear( false ); - -} - - -/** - * WPP uninstall - * - * @return void - * @since 1.0.0 - */ -function wpp_uninstall() { - - // Delete advanced-cache.php file - if ( file_exists( $advanced_cache = trailingslashit( WP_CONTENT_DIR ) . 'advanced-cache.php' ) ) { - unlink( $advanced_cache ); - // Remove WP_CACHE constant - wpp_define_wp_cache( false ); - } - - // Remove all options from database - Option::removeAll(); - - // Clear everything from the cache directory - Cache::clearEverything(); - -} - - -/** - * Compatibility check - * - * @since 1.0.0 - * @return void - */ -function wpp_compatibility_check() { - - // Cache plugins - $incompatiblePlugins = [ - 'w3-total-cache/w3-total-cache.php', - 'wp-super-cache/wp-cache.php', - 'wp-fastest-cache/wpFastestCache.php', - 'wp-rocket/wp-rocket.php', - 'litespeed-cache/litespeed-cache.php', - 'comet-cache/comet-cache.php', - 'breeze/breeze.php', - 'super-static-cache/super-static-cache.php', - 'simple-cache/simple-cache.php', - 'gator-cache/gator-cache.php', - 'hyper-cache/plugin.php', - 'hyper-cache-extended/plugin.php', - 'cache-enabler/cache-enabler.php', - 'cachify/cachify.php', - 'wp-speed-of-light/wp-speed-of-light.php', - 'wp-ffpc/wp-ffpc.php', - 'swift-performance-lite/performance.php', - 'swift-performance/performance.php', - 'hummingbird-performance/wp-hummingbird.php', - ]; - - // Minify plugins - if ( - Option::boolval( 'css_minify' ) - || Option::boolval( 'js_minify' ) - || Option::boolval( 'css_combine' ) - || Option::boolval( 'js_combine' ) - || apply_filters( 'wpp_minify_html', true ) - ) { - - $incompatiblePlugins = array_merge( $incompatiblePlugins, [ - 'autoptimize/autoptimize.php', - 'bwp-minify/bwp-minify.php', - 'wp-minify-fix/wp-minify.php', - 'minqueue/plugin.php', - 'optimize-javascript/pfeiffers-merge-scripts.php', - 'minify-html-markup/minify-html.php', - 'scripts-to-footerphp/scripts-to-footer.php', - 'footer-javascript/footer-javascript.php', - 'combine-js/combine-js.php', - 'js-css-script-optimizer/js-css-script-optimizer.php', - 'scripts-gzip/scripts_gzip.php', - 'dependency-minification/dependency-minification.php', - 'css-optimizer/bpminifycss.php', - 'merge-minify-refresh/merge-minify-refresh.php', - 'async-js-and-css/asyncJSandCSS.php', - 'wp-js/wp-js.php', - 'fast-velocity-minify/fvm.php', - 'wp-asset-clean-up/wpacu.php' - ] ); - - } - - $plugins = apply_filters( 'wpp_incompatible_plugins', $incompatiblePlugins ); - - $incompatible = []; - - // Check active plugins - foreach ( get_option( 'active_plugins' ) as $plugin ) { - if ( in_array( $plugin, $plugins ) ) { - $incompatible[] = $plugin; - wpp_log( sprintf( 'Incompatible plugin %s', $plugin ) ); - } - } - - // Print notices - if ( ! empty( $incompatible ) ) { - - $notice = '
    ' . __( 'The following plugins are not compatible with', 'wpp' ) . ' ' . WPP_PLUGIN_NAME . '
    '; - - foreach ( $incompatible as $plugin ) { - - $data = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin ); - - $notice .= '
    ' . $data[ 'Name' ]; - $notice .= '' . __( 'Deactivate', 'wpp' ) . ''; - $notice .= '
    '; - } - - wpp_notify( $notice, 'error', false ); - - } - -} - - -/** - * Deactivate incompatible plugin - * - * @return void - * @since 1.0.0 - */ -function wpp_deactivate_incompatible_plugin() { - - if ( wp_verify_nonce( Input::get( '_wpnonce' ), 'deactivate' ) ) { - - deactivate_plugins( Input::get( 'plugin' ) ); - wpp_log( sprintf( 'Incompatible plugin %s deactivated', Input::get( 'plugin' ) ) ); - - $redirect_url = wp_get_referer(); - $url_query = parse_url( $redirect_url, PHP_URL_QUERY ); - - parse_str( $url_query, $args ); - - if ( isset( $args[ 'page' ] ) ) { - /** - * Check if plugin name is in referrer URL so we don't redirect to the non-existent admin page after we deactivate the plugin. - * This is not 100% accurate, but it will handle well most cases - */ - if ( stristr( Input::get( 'plugin' ), $args[ 'page' ] ) ) { - $redirect_url = admin_url(); - } - - } - - wp_safe_redirect( $redirect_url ); - - } - -} - - -/** - * Define WP_CACHE constant - * - * @param boolean $cache - * @return void - * @since 1.1.4 - */ -function wpp_define_wp_cache( $cache = true ) { - - $wp_config = trailingslashit( ABSPATH ) . 'wp-config.php'; - - if ( file_exists( $wp_config ) && is_readable( $wp_config ) ) { - - $found = false; - $code = file( $wp_config ); - - foreach( $code as $i => $line ) { - - if ( strstr( $line, 'WP_CACHE' ) ) { - - $found = true; - - $expression = ( $cache ) - ? 'define( "WP_CACHE", true ); // WP Performance' . PHP_EOL - : ''; - - // Defined on the same line as opening PHP tag? - if ( strstr( $line, ' -* @package WPP -*/ - -use WPP\File; -use WPP\Input; -use WPP\Option; - - -/** - * Get the server software - * - * @param mixed $test - * @return string(apache|nginx|unknown)|boolean - * @since 1.0.2 - */ -function wpp_get_server_software( $test = null ) { - - // Apache - if ( preg_match( '#(apache|litespeed|shellrent)#i', Input::server( 'SERVER_SOFTWARE' ) ) ) { - - if ( ! is_null( $test ) ) { - return ( $test === 'apache' ); - } - - return 'apache'; - } - - // Nginx - if ( preg_match( '#(nginx|flywheel)#i', Input::server( 'SERVER_SOFTWARE' ) ) ) { - - if ( ! is_null( $test ) ) { - return ( $test === 'nginx' ); - } - - return 'nginx'; - - } - - return ( ! is_null( $test ) ) - ? false - : 'unknown'; -} - -/** - * Get Nginx rewrite rules - * - * @return string - * @since 1.0.2 - */ -function wpp_get_nginx_rewrite_rules() { - - $output = ''; - - // Browser cache - if ( Option::boolval( 'browser_cache' ) ) { - $output .= File::get( WPP_DATA_DIR . 'definitions/expire.nginx.txt' ); - } - - // Gzip - if ( Option::boolval( 'gzip_compression' ) ) { - $output .= File::get( WPP_DATA_DIR . 'definitions/gzip.nginx.txt' ); - } - - // Cache - if ( - Option::boolval( 'cache' ) - && get_option( 'permalink_structure' ) - && ! is_multisite() - ) { - - $definitions = File::get( WPP_DATA_DIR . 'definitions/cache.nginx.txt' ); - $definitions = str_replace( '{CACHEDIR}', WPP_CACHE_DIR, $definitions ); - $definitions = str_replace( '{CACHEDIR_BASENAME}', basename( WPP_CACHE_DIR ), $definitions ); - $definitions = str_replace( '{CONTENT_DIR}', basename( WP_CONTENT_DIR ), $definitions ); - $definitions = str_replace( '{AMP_TAG}', wpp_get_constant( 'WPP_AMP_TAG', 'amp' ), $definitions ); - - // Get excluded user agents - $agents = Option::get( 'user_agents_exclude', [] ); - - // Check if exclude search engines option is on - if ( Option::boolval( 'search_bots_exclude' ) ) { - $agents = array_merge( $agents, wpp_get_search_engines() ); - } - - // Add curent URL to exclude list if user agent is excluded - if ( ! empty( $agents ) ) { - - $agents = array_map( function( $agent ) { - - $agent = trim( $agent ); - - if ( empty( $agent ) ) { - return 'WPP'; - } - - return preg_quote( $agent ); - - }, $agents ); - - $condition = 'if ($http_user_agent ~* (' . implode( '|', $agents ) . ')) { - set $wpp_cache 0; - }'; - - } else { - $condition = ''; - } - - $definitions = str_replace( '{USER_AGENTS}', $condition, $definitions ); - - $output .= $definitions; - - } - - return $output; - -} - - -/** - * Check if current site is a multisite installation on specific server - * - * @param string $server apache|nginx - * @return bool - * @since 1.1.4 - */ -function wpp_is_multisite_on( $server ) { - - $servers = [ - 'apache', - 'nginx' - ]; - - if ( ! in_array( $server, $servers ) ) - return false; - - return wpp_get_server_software( $server ) && is_multisite(); - -} diff --git a/includes/functions/settings.php b/includes/functions/settings.php deleted file mode 100644 index 436fad6..0000000 --- a/includes/functions/settings.php +++ /dev/null @@ -1,545 +0,0 @@ - -* @package WPP -*/ - -use WPP\Cache; -use WPP\File; -use WPP\Input; -use WPP\Option; - -/** - * Export settings file for download - * - * @return void - * @since 1.0.0 - */ -function wpp_export_settings_file() { - - header( 'Content-disposition: attachment; filename=' . site_url() . '.json' ); - header( 'Content-type: application/json' ); - - $options = wpp_get_options(); - - $data = []; - - foreach ( $options as $option_name => $option_value ) { - $name = str_replace( wpp_get_prefix(), '', $option_name ); - $data[ $name ] = Option::get( $name ); - } - - wpp_log( 'Settings exported' ); - - exit( json_encode( $data ) ); - -} - - -/** - * Import settings - * - * @param array $file - * @return void - * @since 1.0.0 - */ -function wpp_import_settings( $file ) { - - if ( - $file[ 'wpp_import_settings' ][ 'error' ] == 0 - && file_exists( $file[ 'wpp_import_settings' ][ 'tmp_name' ] ) - ) { - - if ( $file[ 'wpp_import_settings' ][ 'type' ] !== 'application/json' ) { - - wpp_notify( 'Invalid settings file', 'warning' ); - - } else { - - $data = json_decode( file_get_contents( $file[ 'wpp_import_settings' ][ 'tmp_name' ] ), true ); - - if ( ! empty( $data ) ) { - - $options = wpp_get_options(); - $list_options = wpp_get_list_options(); - - foreach( $data as $option => $value ) { - - if ( array_key_exists( wpp_get_prefix( $option ), $options ) ) { - - if ( ! in_array( $option, $list_options ) ) { - Option::update( $option, $value ); - } - } - - } - - wpp_log( 'Settings imported' ); - - Cache::clear(); - - } - - } - - } - -} - - - -/** - * Save plugin settings - * - * @param boolean $notify - * @return void - * @since 1.0.0 - */ -function wpp_save_settings( $notify = true ) { - - // Cache - Option::update( 'cache', Input::post( 'cache', 'boolean' ) ); - Option::update( 'cache_time', Input::post( 'cache_time', 'number_int' ) ); - Option::update( 'cache_length', Input::post( 'cache_length', 'number_int' ) ); - Option::update( 'update_clear', Input::post( 'update_clear', 'boolean' ) ); - Option::update( 'save_clear', Input::post( 'save_clear', 'boolean' ) ); - Option::update( 'delete_clear', Input::post( 'delete_clear', 'boolean' ) ); - Option::update( 'mobile_cache', Input::post( 'mobile_cache', 'boolean' ) ); - Option::update( 'clear_assets', Input::post( 'clear_assets', 'boolean' ) ); - Option::update( 'cache_url_exclude', Input::post( 'cache_url_exclude', 'string', FILTER_REQUIRE_ARRAY ) ); - Option::update( 'browser_cache', Input::post( 'browser_cache', 'boolean' ) ); - Option::update( 'gzip_compression', Input::post( 'gzip_compression', 'boolean' ) ); - Option::update( 'sitemaps_list', Input::post( 'sitemaps_list', 'string', FILTER_REQUIRE_ARRAY ) ); - Option::update( 'user_agents_exclude', Input::post( 'user_agents_exclude', 'string', FILTER_REQUIRE_ARRAY ) ); - Option::update( 'search_bots_exclude', Input::post( 'search_bots_exclude', 'boolean' ) ); - - // HTML - Option::update( 'html_optimization', Input::post( 'html_optimization', 'boolean' ) ); - Option::update( 'html_minify_normal', Input::post( 'html_minify_normal', 'boolean' ) ); - Option::update( 'html_minify_aggressive', Input::post( 'html_minify_aggressive', 'boolean' ) ); - Option::update( 'html_remove_comments', Input::post( 'html_remove_comments', 'boolean' ) ); - Option::update( 'html_remove_link_type', Input::post( 'html_remove_link_type', 'boolean' ) ); - Option::update( 'html_remove_script_type', Input::post( 'html_remove_script_type', 'boolean' ) ); - Option::update( 'html_remove_qoutes', Input::post( 'html_remove_qoutes', 'boolean' ) ); - Option::update( 'html_url_exclude', Input::post( 'html_url_exclude', 'string', FILTER_REQUIRE_ARRAY ) ); - - // CSS - Option::update( 'css_minify', Input::post( 'css_minify', 'string', FILTER_REQUIRE_ARRAY ) ); - Option::update( 'css_minify_inline', Input::post( 'css_minify_inline', 'boolean' ) ); - Option::update( 'css_combine', Input::post( 'css_combine', 'string', FILTER_REQUIRE_ARRAY ) ); - Option::update( 'css_inline', Input::post( 'css_inline', 'string', FILTER_REQUIRE_ARRAY ) ); - Option::update( 'css_disable', Input::post( 'css_disable', 'string', FILTER_REQUIRE_ARRAY ) ); - Option::update( 'css_disable_position', Input::post( 'css_disable_position', 'string', FILTER_REQUIRE_ARRAY ) ); - Option::update( 'css_disable_selected', Input::post( 'css_disable_selected', 'string', FILTER_REQUIRE_ARRAY ) ); - Option::update( 'css_disable_except', Input::post( 'css_disable_except', 'string', FILTER_REQUIRE_ARRAY ) ); - Option::update( 'css_defer', Input::post( 'css_defer', 'boolean' ) ); - Option::update( 'css_prefetch', Input::post( 'css_prefetch', 'string', FILTER_REQUIRE_ARRAY ) ); - Option::update( 'css_preconnect', Input::post( 'css_preconnect', 'string', FILTER_REQUIRE_ARRAY ) ); - Option::update( 'css_combine_fonts', Input::post( 'css_combine_fonts', 'boolean' ) ); - Option::update( 'css_font_display', Input::post( 'css_font_display' ) ); - Option::update( 'css_url_exclude', Input::post( 'css_url_exclude', 'string', FILTER_REQUIRE_ARRAY ) ); - Option::update( 'css_file_exclude', Input::post( 'css_file_exclude', 'string', FILTER_REQUIRE_ARRAY ) ); - Option::update( 'css_custom_path_def', stripslashes( Input::post( 'css_custom_path_def' ) ) ); - Option::update( 'css_disable_loggedin', Input::post( 'css_disable_loggedin', 'boolean' ) ); - - // JavaScript - Option::update( 'js_minify', Input::post( 'js_minify', 'string', FILTER_REQUIRE_ARRAY ) ); - Option::update( 'js_minify_inline', Input::post( 'js_minify_inline', 'boolean' ) ); - Option::update( 'js_combine', Input::post( 'js_combine', 'string', FILTER_REQUIRE_ARRAY ) ); - Option::update( 'js_inline', Input::post( 'js_inline', 'string', FILTER_REQUIRE_ARRAY ) ); - Option::update( 'js_defer', Input::post( 'js_defer', 'boolean' ) ); - Option::update( 'js_prefetch', Input::post( 'js_prefetch', 'string', FILTER_REQUIRE_ARRAY ) ); - Option::update( 'js_preconnect', Input::post( 'js_preconnect', 'string', FILTER_REQUIRE_ARRAY ) ); - Option::update( 'js_url_exclude', Input::post( 'js_url_exclude', 'string', FILTER_REQUIRE_ARRAY ) ); - Option::update( 'js_disable', Input::post( 'js_disable', 'string', FILTER_REQUIRE_ARRAY ) ); - Option::update( 'js_disable_position', Input::post( 'js_disable_position', 'string', FILTER_REQUIRE_ARRAY ) ); - Option::update( 'js_disable_selected', Input::post( 'js_disable_selected', 'string', FILTER_REQUIRE_ARRAY ) ); - Option::update( 'js_disable_except', Input::post( 'js_disable_except', 'string', FILTER_REQUIRE_ARRAY ) ); - Option::update( 'js_file_exclude', Input::post( 'js_file_exclude', 'string', FILTER_REQUIRE_ARRAY ) ); - Option::update( 'js_disable_loggedin', Input::post( 'js_disable_loggedin', 'boolean' ) ); - - // Images - Option::update( 'images_resp', Input::post( 'images_resp', 'boolean' ) ); - Option::update( 'images_force', Input::post( 'images_force', 'boolean' ) ); - Option::update( 'images_lazy', Input::post( 'images_lazy', 'boolean' ) ); - Option::update( 'disable_lazy_mobile', Input::post( 'disable_lazy_mobile', 'boolean' ) ); - Option::update( 'images_containers_ids', Input::post( 'images_containers_ids', 'string', FILTER_REQUIRE_ARRAY ) ); - Option::update( 'images_exclude', Input::post( 'images_exclude', 'string', FILTER_REQUIRE_ARRAY ) ); - Option::update( 'image_url_exclude', Input::post( 'image_url_exclude', 'string', FILTER_REQUIRE_ARRAY ) ); - - // Videos - Option::update( 'videos_lazy', Input::post( 'videos_lazy', 'boolean' ) ); - Option::update( 'video_url_exclude', Input::post( 'video_url_exclude', 'string', FILTER_REQUIRE_ARRAY ) ); - - // Media - Option::update( 'disable_emoji', Input::post( 'disable_emoji', 'boolean' ) ); - Option::update( 'disable_embeds', Input::post( 'disable_embeds', 'boolean' ) ); - - // Settings - Option::update( 'enable_log', Input::post( 'enable_log', 'boolean' ) ); - - // CDN - Option::update( 'cdn', Input::post( 'cdn', 'boolean' ) ); - Option::update( 'cdn_hostname', Input::post( 'cdn_hostname', 'url' ) ); - Option::update( 'cdn_exclude', Input::post( 'cdn_exclude', 'string', FILTER_REQUIRE_ARRAY ) ); - - // Database - Option::update( 'db_cleanup_transients', Input::post( 'db_cleanup_transients', 'boolean' ) ); - Option::update( 'db_cleanup_revisions', Input::post( 'db_cleanup_revisions', 'boolean' ) ); - Option::update( 'db_cleanup_spam', Input::post( 'db_cleanup_spam', 'boolean' ) ); - Option::update( 'db_cleanup_trash', Input::post( 'db_cleanup_trash', 'boolean' ) ); - Option::update( 'db_cleanup_cron', Input::post( 'db_cleanup_cron', 'boolean' ) ); - Option::update( 'db_cleanup_autodrafts', Input::post( 'db_cleanup_autodrafts', 'boolean' ) ); - - // Cleanup schedule - $frequency = Input::post( 'automatic_cleanup_frequency' ); - - if ( Option::get( 'db_cleanup_frequency' ) != $frequency ) { - - Option::update( 'db_cleanup_frequency', $frequency ); - - $schedules = wpp_get_cron_schedules(); - - if ( array_key_exists( $frequency, $schedules ) ) { - Option::update( 'db_cleanup_next', ( time() + $schedules[ $frequency ][ 'interval' ] ) ); - } else { - Option::remove( 'db_cleanup_next' ); - } - - } - - // Update htaccess - if ( wpp_get_server_software( 'apache' ) ) { - - // Browser cache - wpp_update_htaccess( - is_multisite() - ? true - : Input::post( 'browser_cache', 'boolean' ), 'expire' - ); - - // Gzip compression - wpp_update_htaccess( - is_multisite() - ? true - : Input::post( 'gzip_compression', 'boolean' ), 'gzip' - ); - - // Htaccess load cache - if ( ! is_multisite() ) { - wpp_update_htaccess( Input::post( 'cache', 'boolean' ), 'cache' ); - } - - } - - - // Save configuration settings - $settings = array_diff_key( $_POST, [ - 'wpp-tab' => true, - 'wpp-nonce' => true, - '_wp_http_referer' => true, - 'wpp-save-settings' => true - ] ); - - $timestamp = time(); - - File::save( WPP_CACHE_DIR . $timestamp . '.' . md5( site_url() ) . '.settings.json', json_encode( $settings ) ); - - Option::update( 'current_settings', $timestamp ); - - // Site settings - $exclude_urls = Input::post( 'cache_url_exclude', 'string', FILTER_REQUIRE_ARRAY ); - - if ( Input::post( 'search_bots_exclude' ) ) { - $exclude_urls = array_merge( $exclude_urls, wpp_get_search_engines() ); - } - - $settings = [ - 'cache' => boolval( Input::post( 'cache' ) ), - 'disable' => Option::boolval( 'wpp_disable' ), - 'mobile_cache' => boolval( Input::post( 'mobile_cache' ) ), - 'expire' => time() + intval( Input::post( 'cache_time', 'number_int' ) * Input::post( 'cache_length', 'number_int' ) ), - 'exclude' => apply_filters( 'wpp_exclude_urls', $exclude_urls ), - 'permalinks' => boolval( get_option( 'permalink_structure' ) ) - ]; - - File::saveSiteSettings( $settings ); - - - /** - * Save settings hook - * @since 1.1.0 - */ - do_action( 'wpp-save-settings' ); - - // Clear cache - if ( Input::post( 'save_clear', 'boolean' ) ) { - Cache::clear(); - } - - if ( $notify ) wpp_notify( 'Settings saved' ); - -} - - -/** - * Load saved settings from file - * - * @param string $filename - * @param boolean $notify - * @return void - * @since 1.0.0 - */ -function wpp_load_settings( $filename, $notify = true ) { - - if ( file_exists( $file = WPP_CACHE_DIR . basename( $filename ) . '.' . md5( site_url() ) . '.settings.json' ) ) { - - $options = Option::getAll(); - $settings = File::getJson( $file ); - - foreach( $options as $option => $value ) { - - $action = ! empty( $value ) - ? 'add' - : 'remove'; - - $option = str_replace( wpp_get_prefix(), '', $option ); - - $value = isset( $settings[ $option ] ) - ? $settings[ $option ] - : null; - - switch ( $option ) { - - case 'automatic_cleanup_frequency': - - Option::update( 'db_cleanup_frequency', $value ); - - break; - - case 'browser_cache': - - if ( wpp_get_server_software( 'apache' ) ) - wpp_update_htaccess( $action, 'expire' ); - - break; - - case 'gzip_compression': - - if ( wpp_get_server_software( 'apache' ) ) - wpp_update_htaccess( $action, 'gzip' ); - - break; - } - - Option::update( $option, $value ); - - } - - Option::update( 'current_settings', $filename ); - - if ( $notify ) wpp_notify( 'Settings file loaded' ); - - } - -} - - -/** - * Save page metabox options - * - * @param integer $post_id - * @return void - * @since 1.0.3 - */ -function wpp_save_post_options( $post_id ) { - - $option_names = [ - 'cache_post_exclude', - 'html_post_exclude', - 'css_post_exclude', - 'js_post_exclude', - 'image_post_exclude', - 'video_post_exclude' - ]; - - foreach( $option_names as $option ) { - - $options = Option::get( $option, [] ); - - if ( Input::post( $option ) ) { - - if ( ! in_array( $post_id, $options ) ) { - $options[] = $post_id; - } - - } else { - $options = array_diff( $options, [ $post_id ] ); - } - - Option::update( $option, $options ); - - } - -} - -/** - * Remove post options added trough metabox - * - * @return void - * @since 1.0.3 - */ -function wpp_ajax_remove_post_options() { - - check_ajax_referer( 'wpp-ajax', 'nonce' ); - - $options = [ - 'js' => 'js_post_exclude', - 'css' => 'css_post_exclude', - 'html' => 'html_post_exclude', - 'cache' => 'cache_post_exclude', - 'image' => 'image_post_exclude', - 'video' => 'video_post_exclude' - ]; - - if ( array_key_exists( Input::post( 'type' ), $options ) ) { - - $option = $options[ Input::post( 'type' ) ]; - $option_data = Option::get( $option, [] ); - $option_data = array_diff( $option_data, [ Input::post( 'id' ) ] ); - - Option::update( $option, $option_data ); - - } - - exit; - -} - -/** - * Get options prefix - * - * @string $name - * @since 1.0.0 - * @return string - */ -function wpp_get_prefix( $name = '' ) { - return sprintf( '%s_%s', 'wpp', $name ); -} - - -/** - * Delete list options - * Used after clearing the cache - * - * @return void - * @since 1.0.0 - */ -function wpp_delete_list_options() { - - $options = wpp_get_list_options(); - - foreach ( $options as $option ) { - Option::remove( $option ); - } - - wpp_log( 'List options deleted' ); - -} - - -/** - * Get list options - * - * @return array - * @since 1.0.0 - */ -function wpp_get_list_options() { - - $defaults = [ - 'plugin_css_list', - 'theme_css_list', - 'plugin_js_list', - 'theme_js_list', - 'external_css_list', - 'external_js_list', - 'prefetch_css_list', - 'prefetch_js_list', - 'css_custom_path_def' - ]; - - /** - * Filter options list which will be deleted after clearing the cache - * @since 1.0.0 - */ - $options = apply_filters( 'wpp-delete-list-options', $defaults ); - - return $options; - -} - - -/** - * Get options - * - * @return array - * @since 1.0.0 - */ -function wpp_get_options() { - - $options = []; - - // Get all options - $result = $GLOBALS[ 'wpdb' ]->get_results( sprintf( - 'SELECT option_name, option_value FROM %s WHERE option_name LIKE "%s%%"', - $GLOBALS['wpdb']->options, - wpp_get_prefix() - ) ); - - foreach( $result as $row ) { - $options[ $row->option_name ] = $row->option_value; - } - - return $options; - -} - - -/** - * Clear files list and cache - * - * @param string $list - * @param boolean $notify - * @return void - * @since 1.0.2 - */ -function wpp_delete_files_list( $type, $notify = true ) { - - $type = str_replace( 'javascript', 'js', $type ); - - if ( ! in_array( $type, [ 'js', 'css' ] ) ) { - return false; - } - - $list_names = [ - sprintf( 'theme_%s_list', $type ), - sprintf( 'plugin_%s_list', $type ), - sprintf( 'external_%s_list', $type ), - sprintf( 'prefetch_%s_list', $type ) - ]; - - foreach ( wpp_get_list_options() as $option ) { - if ( in_array( $option, $list_names ) ) { - Option::remove( $option ); - } - } - - wpp_log( sprintf( '%s list files cleared', $type ) ); - - Cache::clear(); - - if ( $notify ) wpp_notify( 'Files list cleared' ); - -} diff --git a/includes/functions/url.php b/includes/functions/url.php deleted file mode 100644 index 205e8e4..0000000 --- a/includes/functions/url.php +++ /dev/null @@ -1,100 +0,0 @@ - -* @package WPP -*/ - - -/** - * Check if site is on localhost or .dev domain - * - * @return boolean - * @since 1.0.0 - */ -function wpp_is_localhost() { - - $host = parse_url( site_url(), PHP_URL_HOST ); - - if ( 'localhost' === $host || pathinfo( $host, PATHINFO_EXTENSION ) === 'dev' ) { - return true; - } - - return false; - -} - -/** - * Get file hostname - * - * @since 1.0.0 - * @return string - */ -function wpp_get_file_hostname( $file ) { - - if ( $host = parse_url( $file, PHP_URL_HOST ) ) { - return $host; - } - - return $file; - -} - - - -/** - * Replace wildcards with regex pattern - * - * @since 1.0.0 - * @return string - */ -function wpp_url_replace_wildcards( $pattern ) { - - $pattern = preg_quote( $pattern ); - - $wildcards = [ - '{any}' => '[^/]+', - '{numbers}' => '[0-9]+', - '{letters}' => '[A-Za-z]+', - '{all}' => '.*' - ]; - - return str_replace( array_keys( $wildcards ), array_values( $wildcards ), stripslashes( $pattern ) ); - -} - - -/** - * Check if url is found in excluded urls list - * - * @param string $url - * @param array $excluded_urls - * @return boolean - * @since 1.0.9 - */ -function wpp_is_url_excluded( $url, $excluded_urls ) { - - foreach( $excluded_urls as $excluded_url ) { - - $excluded_url = trailingslashit( wpp_url_replace_wildcards( $excluded_url ) ); - - // Try simple match first - if ( $excluded_url == $url ) { - return true; - } - - // if ( stristr( $url, $excluded_url ) ) { - // return true; - // } - - preg_match( '#^' . $excluded_url . '$#', trailingslashit( $url ), $match ); - - if ( isset( $match[0] ) ) { - return true; - } - - } - - return false; -} \ No newline at end of file diff --git a/includes/index.php b/includes/index.php deleted file mode 100644 index e71af0e..0000000 --- a/includes/index.php +++ /dev/null @@ -1 +0,0 @@ - -* @package WPP -*/ - -foreach( [ WPP_FUNCTIONS_DIR . '*.php', WPP_ADDONS_DIR . '*/init.php' ] as $dir ) { - - foreach( glob( $dir ) as $file ) { - include_once $file; - } - -} diff --git a/languages/wpp-hr-wpp-admin.json b/languages/wpp-hr-wpp-admin.json new file mode 100644 index 0000000..c84db6f --- /dev/null +++ b/languages/wpp-hr-wpp-admin.json @@ -0,0 +1,926 @@ +{ + "translation-revision-date": "2026-08-18 12:27+0000", + "generator": "wp-performance/merge-script-translations", + "domain": "messages", + "locale_data": { + "messages": { + "": { + "domain": "messages", + "lang": "hr", + "plural-forms": "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);" + }, + "%d day ago": [ + "" + ], + "%d hour ago": [ + "" + ], + "%d minute ago": [ + "" + ], + "%s settings": [ + "" + ], + "A post or page is deleted": [ + "Stranica ili post je izbrisan" + ], + "A post or page is published or updated": [ + "" + ], + "API key": [ + "API ključ" + ], + "About": [ + "" + ], + "Above-the-fold CSS, inlined and applied before the async stylesheet loads.": [ + "" + ], + "Account email": [ + "E-pošta računa" + ], + "Active": [ + "" + ], + "Active optimizations": [ + "" + ], + "Add": [ + "" + ], + "Add Sitemap": [ + "Dodaj XML mapu stranice" + ], + "Add URL": [ + "Dodaj URL" + ], + "Add User Agent": [ + "Dodaj korisničkog agenta" + ], + "Add container": [ + "" + ], + "Add file": [ + "Dodaj datoteku" + ], + "Add image": [ + "" + ], + "Add missing width/height to prevent layout shift (CLS)": [ + "" + ], + "Add origin": [ + "" + ], + "Add selector": [ + "" + ], + "Add size": [ + "Dodaj veličinu" + ], + "Add these rules to your nginx server block, then reload nginx.": [ + "" + ], + "Add-ons": [ + "Dodaci" + ], + "Adds deferred CSS/JS, hosted fonts and modern image formats. Recommended for most sites.": [ + "" + ], + "Aggressive": [ + "" + ], + "Apply": [ + "" + ], + "Apply a curated configuration in one click, then fine-tune any tab.": [ + "" + ], + "Apply this preset? It will overwrite the related settings.": [ + "" + ], + "Apply to all": [ + "" + ], + "Applying…": [ + "" + ], + "Asynchronous CSS": [ + "" + ], + "Asynchronous JavaScript": [ + "" + ], + "Asynchronous JavaScript loading": [ + "" + ], + "Auto Drafts": [ + "Skice" + ], + "Auto-saved draft posts.": [ + "" + ], + "Automatic database cleanup": [ + "Automatsko čišćenje baze podataka" + ], + "Automatically purge Varnish whenever the cache is cleared.": [ + "" + ], + "Back up your database before running any cleanup. These actions cannot be undone.": [ + "" + ], + "Back up your database first. Run this cleanup now?": [ + "" + ], + "Balanced": [ + "" + ], + "Basic (no query string)": [ + "" + ], + "Biggest TBT/INP win: scripts run on first scroll, click, or key press. Exclude anything that must run immediately.": [ + "" + ], + "Brotli": [ + "Brotli" + ], + "Brotli compression": [ + "" + ], + "Browser cache TTL": [ + "" + ], + "Browser cache and gzip rules are written to .htaccess automatically.": [ + "" + ], + "Browser caching": [ + "Predmemorija preglednika" + ], + "CDN": [ + "" + ], + "CDN hostname": [ + "Naziv CDN poslužitelja" + ], + "CSS": [ + "" + ], + "CSS files": [ + "CSS datoteke" + ], + "CSS id or class, e.g. #hero or .no-lazy": [ + "" + ], + "CSS settings": [ + "CSS postavke" + ], + "Cache": [ + "Predmemorija" + ], + "Cache URLs with query strings": [ + "" + ], + "Cache cleared.": [ + "" + ], + "Cache level": [ + "Level predmemorija" + ], + "Cache preloading": [ + "Predučitavanje predmemorije" + ], + "Cache size": [ + "" + ], + "Cache statistics": [ + "Statistika predmemorije" + ], + "Cache status": [ + "" + ], + "Cached pages": [ + "" + ], + "Cancel": [ + "" + ], + "Cleaning…": [ + "" + ], + "Cleanup complete.": [ + "" + ], + "Cleanup failed.": [ + "" + ], + "Clear cache": [ + "Očisti predmemeoriju" + ], + "Clear cache after": [ + "Očisti predmemoriju nakon" + ], + "Clear cache options": [ + "" + ], + "Clear cache when": [ + "Očisti predmemoriju kada" + ], + "Clear log": [ + "" + ], + "Clearing…": [ + "" + ], + "Cloudflare": [ + "Cloudflare" + ], + "Cloudflare error.": [ + "" + ], + "Combine": [ + "Kombinirati" + ], + "Combine Google Fonts into one request": [ + "" + ], + "Compresses resources before sending them to the browser.": [ + "" + ], + "Configure Cloudflare": [ + "" + ], + "Content refreshes automatically every 10 seconds.": [ + "" + ], + "Conversion failed.": [ + "" + ], + "Convert all images to WebP/AVIF? This can take a while.": [ + "" + ], + "Convert existing images": [ + "" + ], + "Converting": [ + "" + ], + "Could not add size.": [ + "" + ], + "Could not apply the preset.": [ + "" + ], + "Could not clear the cache.": [ + "" + ], + "Could not clear the log.": [ + "" + ], + "Could not remove size.": [ + "" + ], + "Could not restore settings.": [ + "" + ], + "Could not save settings.": [ + "" + ], + "Could not update the file list.": [ + "" + ], + "Credentials": [ + "" + ], + "Critical CSS": [ + "" + ], + "Crop": [ + "Izreži" + ], + "Custom URLs to purge": [ + "" + ], + "Custom host": [ + "Prilagođeni URL host" + ], + "DNS prefetch": [ + "" + ], + "Daily": [ + "Dnevno" + ], + "Database": [ + "Baza podataka" + ], + "Days": [ + "" + ], + "Default": [ + "" + ], + "Defaults restored.": [ + "" + ], + "Defer JavaScript to remove render-blocking": [ + "" + ], + "Defer offscreen images with native loading=\"lazy\".": [ + "" + ], + "Delay JavaScript until user interaction": [ + "" + ], + "Delay until interaction": [ + "" + ], + "Delete": [ + "Izbriši" + ], + "Delete all": [ + "Izbrisati sve" + ], + "Development mode": [ + "Uključi development mode" + ], + "Disable": [ + "Onesposobiti" + ], + "Disable CSS optimization for logged-in users": [ + "Onemogućite CSS optimizaciju za prijavljene korisnike" + ], + "Disable JavaScript optimization for logged-in users": [ + "Onemogućite JavaScript optimizaciju za prijavljene korisnike" + ], + "Disable WordPress emoji": [ + "" + ], + "Disable lazy load on mobile devices": [ + "Onemogući lazy load na mobilnim uređajima" + ], + "Disable oEmbed discovery": [ + "" + ], + "Disabled": [ + "" + ], + "Download settings file": [ + "" + ], + "Dynamic page prefetch": [ + "" + ], + "Embeds": [ + "Embeds" + ], + "Emoji": [ + "" + ], + "Emoji & Embeds": [ + "" + ], + "Enable CDN": [ + "Omogući CDN" + ], + "Enable HTML optimization": [ + "" + ], + "Enable automatic cleanup": [ + "Omogući automatsko čišćenje" + ], + "Enable cache": [ + "Omogući predmemoriju" + ], + "Enable persistent object cache": [ + "" + ], + "Enable troubleshooting log": [ + "" + ], + "Enter the path to an XML sitemap used to preload the cache.": [ + "" + ], + "Every optimization on, including delayed JavaScript and unused-CSS removal. Test your site after applying.": [ + "" + ], + "Everywhere": [ + "" + ], + "Everywhere except selected URLs": [ + "" + ], + "Exclude URL(s)": [ + "Izuzmi URL" + ], + "Exclude URL(s) from CSS optimization": [ + "Izuzimanje URL-ova iz CSS optimizacije" + ], + "Exclude URL(s) from HTML optimization": [ + "" + ], + "Exclude URL(s) from JavaScript optimization": [ + "Izuzimanje URL-ova iz JavaScript optimizacije" + ], + "Exclude URL(s) from cache": [ + "Izuzimanje URL-ova iz predmemorije" + ], + "Exclude User Agent(s) from cache": [ + "Izuzmite korisničke agente iz predmemorije" + ], + "Exclude by name": [ + "" + ], + "Exclude containers": [ + "" + ], + "Exclude file(s) from CDN": [ + "Izuzmi datoteke iz CDN-a" + ], + "Exclude from async": [ + "" + ], + "Exclude from defer": [ + "" + ], + "Exclude from delay": [ + "" + ], + "Exclude search engines": [ + "Izuzmi tražilice" + ], + "Expired and stale transients.": [ + "" + ], + "Export failed.": [ + "" + ], + "Export settings": [ + "Izvezi postavke" + ], + "Export your configuration to move it between sites, or import a saved configuration file.": [ + "" + ], + "External": [ + "" + ], + "File": [ + "Datoteka" + ], + "File list updated.": [ + "" + ], + "Font display": [ + "" + ], + "Force srcset on images": [ + "" + ], + "Google Fonts": [ + "" + ], + "Google, Bing and other crawlers bypass the cache.": [ + "" + ], + "Gzip compression": [ + "" + ], + "H": [ + "" + ], + "HTML": [ + "" + ], + "HTML files": [ + "HTML datoteke" + ], + "HTML optimization": [ + "" + ], + "Health checks": [ + "" + ], + "Heuristic: keeps rules whose classes/ids appear on the page. The full CSS still loads async as a fallback.": [ + "" + ], + "Host Google Fonts locally and preload them": [ + "" + ], + "Hours": [ + "" + ], + "Image dimensions": [ + "" + ], + "Image size added.": [ + "" + ], + "Image sizes": [ + "Veličine slika" + ], + "Images": [ + "Slike" + ], + "Images converted.": [ + "" + ], + "Import / Export": [ + "" + ], + "Import failed - invalid file.": [ + "" + ], + "Import settings": [ + "Uvezi postavke" + ], + "Inline": [ + "Umetni" + ], + "Inline only used CSS; load the rest async": [ + "" + ], + "Integrate your Cloudflare account to purge cache and manage zone settings.": [ + "" + ], + "JavaScript": [ + "" + ], + "JavaScript files": [ + "JavaScript datoteke" + ], + "JavaScript settings": [ + "JavaScript postavke" + ], + "Keep generated CSS/JS files when clearing the cache": [ + "" + ], + "Lazy load": [ + "Lazy load" + ], + "Lazy load images": [ + "Lazy load slika" + ], + "Lazy load videos & iframes": [ + "" + ], + "Leverage browser caching": [ + "Iskoristite predmemoriju preglednika" + ], + "Load CSS without render-blocking": [ + "" + ], + "Log cleared.": [ + "" + ], + "Log file": [ + "" + ], + "Logged-in users": [ + "" + ], + "Logging": [ + "" + ], + "Media": [ + "Media" + ], + "Minify": [ + "Umanji" + ], + "Minify inline CSS": [ + "Smanji umetnuti CSS" + ], + "Minify inline JavaScript": [ + "Smanjite umetnuti JavaScript" + ], + "Minutes": [ + "" + ], + "Mobile cache": [ + "" + ], + "Monthly": [ + "Mjesečno" + ], + "Name": [ + "Naziv" + ], + "Next run": [ + "Sljedeće čišćenje" + ], + "Next-gen images": [ + "" + ], + "Nginx rules": [ + "" + ], + "No files collected yet. Enable caching or an optimization, visit your site, then choose \"Update files list\".": [ + "" + ], + "No supported object cache backend was detected. Install and enable the Redis PHP extension to use a persistent object cache.": [ + "" + ], + "Normal": [ + "" + ], + "Not scheduled": [ + "Nije zakazano" + ], + "Not set": [ + "Nije postavljeno" + ], + "Number of above-the-fold images to preload (fetchpriority=high) and skip from lazy load. 0 = off.": [ + "" + ], + "Object cache": [ + "" + ], + "Off (recommended): tracking params (utm, gclid, fbclid…) are ignored so only clean URLs are cached.": [ + "" + ], + "Only on selected URLs": [ + "" + ], + "Origins to resolve early, e.g. https://fonts.gstatic.com": [ + "" + ], + "Orphaned cron events.": [ + "" + ], + "Overview": [ + "" + ], + "Page cache, GZIP, browser caching and lazy loading. Works with virtually any theme.": [ + "" + ], + "Plugins": [ + "Dodatci" + ], + "Preconnect": [ + "" + ], + "Prefetch": [ + "" + ], + "Prefetch a page as soon as a visitor hovers over its link.": [ + "" + ], + "Preload LCP images": [ + "" + ], + "Preset applied. Reloading…": [ + "" + ], + "Purge cache": [ + "" + ], + "Purge custom URLs": [ + "" + ], + "Purge everything": [ + "Očisti sve" + ], + "Purging…": [ + "" + ], + "Query strings": [ + "" + ], + "Quick setup": [ + "" + ], + "Recommended": [ + "" + ], + "Records cache and optimization activity to help diagnose issues.": [ + "" + ], + "Redis object cache": [ + "" + ], + "Reduces server response time by serving static HTML files to visitors.": [ + "" + ], + "Regenerate all thumbnails? This may take a while.": [ + "" + ], + "Regenerate thumbnails": [ + "Regenerirajte umanjene slike" + ], + "Regenerating": [ + "" + ], + "Regeneration failed.": [ + "" + ], + "Remove": [ + "Makni" + ], + "Remove HTML comments (conditional comments preserved)": [ + "" + ], + "Remove comments": [ + "" + ], + "Remove quotes": [ + "" + ], + "Remove quotes from attributes where possible": [ + "" + ], + "Remove this image size?": [ + "" + ], + "Remove type attribute": [ + "" + ], + "Remove type=\"text/css\" from link tags": [ + "" + ], + "Remove type=\"text/javascript\" from script tags": [ + "" + ], + "Remove unused CSS": [ + "" + ], + "Resource hints": [ + "" + ], + "Respect existing headers": [ + "" + ], + "Responsive images": [ + "Responzivne slike" + ], + "Restore": [ + "" + ], + "Restore default image sizes?": [ + "" + ], + "Restore defaults": [ + "" + ], + "Restore points": [ + "" + ], + "Restore this saved configuration? Your current settings will be replaced.": [ + "" + ], + "Restoring…": [ + "" + ], + "Revisions": [ + "Revizije" + ], + "Rewrites static asset URLs (CSS, JavaScript, images) to your CDN hostname.": [ + "" + ], + "Rocket Loader": [ + "Rocket Loader" + ], + "Safe": [ + "" + ], + "Save changes": [ + "Spremi izmjene" + ], + "Saving…": [ + "" + ], + "Schedule": [ + "Raspored" + ], + "Scheduled tasks": [ + "Zakazani zadaci" + ], + "Selectors to always keep, e.g. classes toggled by JavaScript.": [ + "" + ], + "Separate cache for mobile devices": [ + "Odvojite predmemoriju za mobilne uređaje" + ], + "Serve WebP/AVIF images": [ + "" + ], + "Serve WebP/AVIF via when a converted file exists. New uploads convert automatically.": [ + "" + ], + "Server": [ + "Poslužitelj" + ], + "Sets HTTP expiry headers so returning visitors load resources from their browser.": [ + "" + ], + "Settings": [ + "Postavke" + ], + "Settings imported. Reloading…": [ + "" + ], + "Settings restored. Reloading…": [ + "" + ], + "Settings saved.": [ + "" + ], + "Simplified (ignore query string)": [ + "" + ], + "Spam": [ + "Spam" + ], + "Spam and trashed comments.": [ + "" + ], + "Stored post revisions.": [ + "" + ], + "Stores WordPress query and option lookups in Redis to cut database load. Installs an object-cache.php drop-in.": [ + "" + ], + "Temporarily bypass the Cloudflare cache (auto-off after 3h)": [ + "" + ], + "The last five saved configurations appear here so you can roll back a change.": [ + "" + ], + "The log is empty.": [ + "" + ], + "Theme": [ + "Tema" + ], + "Thumbnails regenerated.": [ + "" + ], + "Total": [ + "" + ], + "Transients": [ + "Privremene postavke" + ], + "Trash": [ + "Smeće" + ], + "Trashed posts and pages.": [ + "" + ], + "Troubleshooting": [ + "" + ], + "Update files list": [ + "Ažuriraj popis datoteka" + ], + "Updating…": [ + "" + ], + "Use {numbers}, {letters} or {any} to match dynamic parts of a URL.": [ + "" + ], + "Use {numbers}, {letters}, {any} or {all} to match dynamic parts of a URL.": [ + "" + ], + "Used-CSS safelist": [ + "" + ], + "Varnish": [ + "Varnish" + ], + "Videos": [ + "Video" + ], + "W": [ + "" + ], + "WP Performance": [ + "WP Performance" + ], + "WP Performance settings are saved": [ + "" + ], + "Weekly": [ + "Tjedno" + ], + "Yes": [ + "Da" + ], + "Zone ID": [ + "ID Zone" + ], + "Zone settings": [ + "" + ], + "complete.": [ + "" + ], + "is being rebuilt in the next step.": [ + "" + ], + "just now": [ + "" + ], + "name": [ + "" + ] + } + } +} diff --git a/languages/wpp-hr.mo b/languages/wpp-hr.mo index b46fa66..8eefe76 100644 Binary files a/languages/wpp-hr.mo and b/languages/wpp-hr.mo differ diff --git a/languages/wpp-hr.po b/languages/wpp-hr.po index e7ae669..4ab901d 100644 --- a/languages/wpp-hr.po +++ b/languages/wpp-hr.po @@ -1,7 +1,8 @@ msgid "" msgstr "" "Project-Id-Version: WP Performance\n" -"POT-Creation-Date: 2019-08-30 14:57+0200\n" +"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/WP-Performance\n" +"POT-Creation-Date: 2026-05-25T19:59:27+00:00\n" "PO-Revision-Date: 2019-08-30 15:10+0200\n" "Last-Translator: \n" "Language-Team: \n" @@ -9,1383 +10,2211 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" -"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && " +"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" "X-Generator: Poedit 2.0.3\n" "X-Poedit-Basepath: ..\n" "X-Poedit-Flags-xgettext: --add-comments=translators:\n" "X-Poedit-WPHeader: wp-performance.php\n" "X-Poedit-SourceCharset: UTF-8\n" -"X-Poedit-KeywordsList: __;_e;_n:1,2;_x:1,2c;_ex:1,2c;_nx:4c,1,2;esc_attr__;" -"esc_attr_e;esc_attr_x:1,2c;esc_html__;esc_html_e;esc_html_x:1,2c;_n_noop:1,2;" -"_nx_noop:3c,1,2;__ngettext_noop:1,2;wpp_notify\n" +"X-Poedit-KeywordsList: " +"__;_e;_n:1,2;_x:1,2c;_ex:1,2c;_nx:4c,1,2;esc_attr__;esc_attr_e;esc_attr_x:1,2c;esc_html__;esc_html_e;esc_html_x:1,2c;_n_noop:1,2;_nx_noop:3c,1,2;__ngettext_noop:1,2;wpp_notify\n" "X-Poedit-SearchPath-0: .\n" "X-Poedit-SearchPathExcluded-0: *.js\n" -#: includes/addons/cloudflare/cloudflare.php:55 -#, fuzzy -#| msgid "Cloudflare credentials" -msgid "Cloudflare - purge everything" -msgstr "Cloudflare podaci" +#. Plugin Name of the plugin +#: wp-performance.php src/Admin/AdminMenu.php:23 src/Admin/AdminMenu.php:24 +#: src/Admin/Metabox.php:28 assets/admin/app/App.jsx:77 +msgid "WP Performance" +msgstr "WP Performance" + +#. Description of the plugin +#: wp-performance.php +msgid "WP Performance Optimizer - cache & performance plugin." +msgstr "" -#: includes/addons/cloudflare/cloudflare.php:56 -msgid "Cloudflare - purge custom URL(s)" +#. Author of the plugin +#: wp-performance.php +msgid "Ante Laca" msgstr "" -#: includes/addons/cloudflare/cloudflare.php:97 -msgid "Cloudflare API credentials not set" -msgstr "Cloudflare API podaci nisu postavljeni" +#: src/Addons/Cloudflare/CloudflareController.php:87 +msgid "Cloudflare is not configured." +msgstr "" -#: includes/addons/cloudflare/cloudflare.php:116 -msgid " Cloudflare cannot get zone details. Check your Cloudflare credentials" +#: src/Admin/CompatibilityNotice.php:51 +msgid "WP Performance detected another caching/optimization plugin:" msgstr "" -"Cloudflare ne može dobiti detalje zone. Provjerite Cloudflare podatke računa" -#: includes/addons/cloudflare/cloudflare.php:123 -#, php-format +#: src/Admin/CompatibilityNotice.php:53 msgid "" -" Cloudflare zone %s is not activated. Please go to your Cloudflare dashboard " -"and activate it." +"Running more than one can cause conflicts; consider deactivating the others." +msgstr "" + +#: src/Admin/Metabox.php:36 +msgid "Exclude from cache" +msgstr "Izuzmi stranicu iz predmemorije" + +#: src/Admin/Metabox.php:37 +msgid "Exclude from CSS optimization" +msgstr "Izuzmi stranicu iz CSS optimizacije" + +#: src/Admin/Metabox.php:38 +msgid "Exclude from JavaScript optimization" +msgstr "" + +#: src/Admin/Metabox.php:39 +msgid "Exclude from HTML optimization" +msgstr "" + +#: src/Admin/Metabox.php:40 +msgid "Exclude from image optimization" +msgstr "" + +#: src/Admin/Metabox.php:41 +msgid "Exclude from video lazy load" +msgstr "" + +#: src/Cron/CronHooks.php:45 +msgid "Once weekly" +msgstr "" + +#: src/Cron/CronHooks.php:46 +msgid "Once monthly" +msgstr "" + +#: src/Rest/Admin/OverviewController.php:91 +#: src/Rest/Admin/OverviewController.php:120 +#: src/Rest/Admin/OverviewController.php:122 +#: src/Rest/Admin/OverviewController.php:124 +msgid "Page cache" +msgstr "" + +#: src/Rest/Admin/OverviewController.php:92 +#: assets/admin/app/tabs/CacheTab.jsx:207 +msgid "Browser caching" +msgstr "Predmemorija preglednika" + +#: src/Rest/Admin/OverviewController.php:93 +msgid "GZIP compression" +msgstr "" + +#: src/Rest/Admin/OverviewController.php:94 +msgid "CSS optimization" +msgstr "" + +#: src/Rest/Admin/OverviewController.php:95 +msgid "JavaScript optimization" +msgstr "" + +#: src/Rest/Admin/OverviewController.php:96 +msgid "HTML minification" +msgstr "" + +#: src/Rest/Admin/OverviewController.php:97 +msgid "Lazy loading" +msgstr "" + +#: src/Rest/Admin/OverviewController.php:98 +msgid "WebP/AVIF images" +msgstr "" + +#: src/Rest/Admin/OverviewController.php:99 +msgid "Database cleanup" +msgstr "" + +#: src/Rest/Admin/OverviewController.php:100 assets/admin/app/App.jsx:42 +#: assets/admin/app/tabs/SettingsTab.jsx:21 +msgid "CDN" +msgstr "" + +#: src/Rest/Admin/OverviewController.php:101 +#: src/Rest/Admin/OverviewController.php:129 +#: src/Rest/Admin/OverviewController.php:131 +#: src/Rest/Admin/OverviewController.php:133 +#: src/Rest/Admin/OverviewController.php:135 +#: assets/admin/app/tabs/SettingsTab.jsx:205 +msgid "Object cache" +msgstr "" + +#: src/Rest/Admin/OverviewController.php:120 +msgid "Page caching is turned off." +msgstr "" + +#: src/Rest/Admin/OverviewController.php:122 +msgid "Page caching is active and serving cached pages." +msgstr "" + +#: src/Rest/Admin/OverviewController.php:124 +msgid "The advanced-cache.php drop-in or WP_CACHE constant is missing." +msgstr "" + +#: src/Rest/Admin/OverviewController.php:129 +msgid "A persistent object cache is active." +msgstr "" + +#: src/Rest/Admin/OverviewController.php:131 +msgid "Another object cache drop-in is installed." +msgstr "" + +#: src/Rest/Admin/OverviewController.php:133 +msgid "Redis is available but the object cache is not enabled." +msgstr "" + +#: src/Rest/Admin/OverviewController.php:135 +msgid "No object cache backend detected (Redis recommended)." +msgstr "" + +#: src/Rest/Admin/OverviewController.php:140 +#: src/Rest/Admin/OverviewController.php:141 +msgid "Compression" +msgstr "" + +#: src/Rest/Admin/OverviewController.php:140 +msgid "GZIP compression is available." +msgstr "" + +#: src/Rest/Admin/OverviewController.php:141 +msgid "The zlib extension is missing, so GZIP is unavailable." +msgstr "" + +#: src/Rest/Admin/OverviewController.php:150 +#: src/Rest/Admin/OverviewController.php:151 +msgid "PHP OPcache" +msgstr "" + +#: src/Rest/Admin/OverviewController.php:150 +msgid "OPcache is enabled." +msgstr "" + +#: src/Rest/Admin/OverviewController.php:151 +msgid "OPcache is not enabled. Enabling it speeds up PHP execution." +msgstr "" + +#. translators: %s: PHP version. +#: src/Rest/Admin/OverviewController.php:155 +#: src/Rest/Admin/OverviewController.php:156 +msgid "PHP version" msgstr "" -"Cloudflare zona %s nije aktivirana. Idite u svoju Cloudflare nadzornu ploču " -"i aktivirajte je." -#: includes/addons/cloudflare/cloudflare.php:127 +#. translators: %s: PHP version. +#: src/Rest/Admin/OverviewController.php:155 #, php-format -msgid "" -" Cloudflare zone %s status is pending and these settings won't have any " -"effect on your website." +msgid "Running PHP %s." msgstr "" -"Cloudflare zona %s je na čekanju i ove postavke neće imati nikakvog utjecaja " -"na vašu web-lokaciju." -#: includes/addons/cloudflare/cloudflare.php:142 -msgid " Cloudflare development mode not set" -msgstr "Cloudflare razvojni mod nije postavljen" +#. translators: 1: current PHP version, 2: recommended version. +#: src/Rest/Admin/OverviewController.php:156 +#, php-format +msgid "PHP %1$s is below the recommended %2$s." +msgstr "" -#: includes/addons/cloudflare/cloudflare.php:151 -msgid " Cloudflare cache level not set" -msgstr "Cloudflare level predmemorije nije postavljen" +#: src/Rest/Admin/OverviewController.php:162 +#: src/Rest/Admin/OverviewController.php:163 +msgid "Cache directory" +msgstr "" -#: includes/addons/cloudflare/cloudflare.php:161 -msgid " Cloudflare browser cache expiration not set" -msgstr "Cloudflare istek predmemorije preglednika nije postavljen" +#: src/Rest/Admin/OverviewController.php:162 +msgid "The cache directory is writable." +msgstr "" -#: includes/addons/cloudflare/cloudflare.php:175 -msgid " Cloudflare minify not set" -msgstr "Cloudflare minifikacija nije postavljena" +#: src/Rest/Admin/OverviewController.php:163 +msgid "The cache directory is not writable." +msgstr "" -#: includes/addons/cloudflare/cloudflare.php:187 -msgid " Cloudflare Rocket loader mode not set" -msgstr " Cloudflare Rocket loader mod nije postavljen" +#: src/Rest/Admin/OverviewController.php:167 +#: src/Rest/Admin/OverviewController.php:168 +msgid "Image conversion" +msgstr "" -#: includes/addons/cloudflare/cloudflare.php:197 -msgid " Cloudflare Brotli mode not set" -msgstr " Cloudflare Brotli mod nije postavljen" +#: src/Rest/Admin/OverviewController.php:167 +msgid "GD can generate WebP images." +msgstr "" -#: includes/addons/cloudflare/cloudflare.php:209 -msgid "Cloudflare settings saved" -msgstr "Cloudflare postavke spremljene" +#: src/Rest/Admin/OverviewController.php:168 +msgid "GD cannot generate WebP images on this server." +msgstr "" -#: includes/addons/cloudflare/cloudflare.php:231 -msgid "Something went wrong. Cannot purge Cloudflare cache" +#: src/Rest/Admin/OverviewController.php:175 +#: src/Rest/Admin/OverviewController.php:176 +#: src/Rest/Admin/OverviewController.php:178 +#: src/Rest/Admin/OverviewController.php:180 +msgid "Server rules" msgstr "" -#: includes/addons/cloudflare/cloudflare.php:261 -msgid "Something went wrong. Cannot purge Cloudflare custom URL(s) cache" +#: src/Rest/Admin/OverviewController.php:175 +msgid "Apache detected; .htaccess is writable." msgstr "" -#: includes/addons/cloudflare/views/addon.php:20 -msgid "Integrate your Cloudflare account with this add-on." -msgstr "S ovim dodatkom integrirajte svoj račun za Cloudflare." +#: src/Rest/Admin/OverviewController.php:176 +msgid "Apache detected but .htaccess is not writable." +msgstr "" -#: includes/addons/cloudflare/views/addon.php:27 -#: includes/addons/cloudflare/views/admin.php:82 -#: includes/addons/cloudflare/views/admin.php:175 -#: includes/addons/cloudflare/views/admin.php:187 -#: includes/addons/prefetch/views/addon.php:18 -#: includes/addons/varnish/views/addon.php:49 includes/functions/admin.php:267 -#: includes/functions/backend.php:238 -msgid "Enable" -msgstr "Omogući" +#: src/Rest/Admin/OverviewController.php:178 +msgid "Nginx detected; add the generated rules from Settings." +msgstr "" -#: includes/addons/cloudflare/views/admin.php:15 -msgid "Caching" -msgstr "Predmemorija" +#: src/Rest/Admin/OverviewController.php:180 +msgid "Server type could not be determined." +msgstr "" -#: includes/addons/cloudflare/views/admin.php:21 -msgid "Purge Cache" -msgstr "Očisti predmemoriju" +#: src/Rest/Admin/SettingsController.php:64 +#: src/Rest/Admin/SettingsController.php:73 +msgid "Unknown settings group." +msgstr "" -#: includes/addons/cloudflare/views/admin.php:23 -msgid "Clear all Cloudflare cache" -msgstr "Očisti Cloudflare predmemoriju" +#: assets/admin/app/App.jsx:35 +msgid "Overview" +msgstr "" -#: includes/addons/cloudflare/views/admin.php:23 -msgid "Purge everything" -msgstr "Očisti sve" +#: assets/admin/app/App.jsx:36 assets/admin/app/tabs/SettingsTab.jsx:15 +msgid "Cache" +msgstr "Predmemorija" -#: includes/addons/cloudflare/views/admin.php:24 -msgid "Clear custom URL(s) from Cloudflare cache" +#: assets/admin/app/App.jsx:37 assets/admin/app/tabs/SettingsTab.jsx:16 +msgid "CSS" msgstr "" -#: includes/addons/cloudflare/views/admin.php:24 -#: includes/addons/cloudflare/views/admin.php:29 -msgid "Purge custom URL(s)" +#: assets/admin/app/App.jsx:38 assets/admin/app/tabs/SettingsTab.jsx:17 +msgid "JavaScript" msgstr "" -#: includes/addons/cloudflare/views/admin.php:49 includes/admin/cache.php:116 -#: includes/admin/cache.php:335 includes/admin/cache.php:355 -#: includes/admin/cache.php:414 includes/admin/cdn.php:66 -#: includes/admin/css.php:317 includes/admin/css.php:327 -#: includes/admin/includes/external_files.php:66 -#: includes/admin/includes/external_files.php:94 -#: includes/admin/includes/local_files.php:65 -#: includes/admin/includes/local_files.php:92 includes/admin/javascript.php:243 -#: includes/admin/javascript.php:253 includes/admin/media.php:66 -#: includes/admin/media.php:92 includes/admin/media.php:136 -#: includes/admin/media.php:156 includes/admin/media.php:238 -#: includes/admin/media.php:258 includes/functions/miscellaneous.php:258 +#: assets/admin/app/App.jsx:39 assets/admin/app/tabs/SettingsTab.jsx:18 +msgid "HTML" +msgstr "" + +#: assets/admin/app/App.jsx:40 assets/admin/app/tabs/SettingsTab.jsx:19 +msgid "Media" +msgstr "Media" + +#: assets/admin/app/App.jsx:41 assets/admin/app/tabs/SettingsTab.jsx:20 +msgid "Database" +msgstr "Baza podataka" + +#: assets/admin/app/App.jsx:43 assets/admin/app/tabs/SettingsTab.jsx:22 +msgid "Settings" +msgstr "Postavke" + +#: assets/admin/app/App.jsx:44 +msgid "Add-ons" +msgstr "Dodaci" + +#: assets/admin/app/App.jsx:50 assets/admin/app/tabs/AddonsTab.jsx:35 +#: assets/admin/app/tabs/SettingsTab.jsx:23 +msgid "Cloudflare" +msgstr "Cloudflare" + +#: assets/admin/app/components/fields/RepeatableInput.jsx:11 +#: assets/admin/app/components/ImageSizes.jsx:156 +#: assets/admin/app/tabs/JsTab.jsx:77 +msgid "Add" +msgstr "" + +#: assets/admin/app/components/fields/RepeatableInput.jsx:37 +#: assets/admin/app/components/ImageSizes.jsx:114 msgid "Remove" msgstr "Makni" -#: includes/addons/cloudflare/views/admin.php:58 -#: includes/addons/cloudflare/views/admin.php:67 +#: assets/admin/app/components/FileListTable.jsx:8 +msgid "Theme" +msgstr "Tema" + +#: assets/admin/app/components/FileListTable.jsx:9 +msgid "Plugins" +msgstr "Dodatci" + +#: assets/admin/app/components/FileListTable.jsx:10 +msgid "External" +msgstr "" + +#: assets/admin/app/components/FileListTable.jsx:14 +msgid "Everywhere" +msgstr "" + +#: assets/admin/app/components/FileListTable.jsx:15 +msgid "Only on selected URLs" +msgstr "" + +#: assets/admin/app/components/FileListTable.jsx:16 +msgid "Everywhere except selected URLs" +msgstr "" + +#: assets/admin/app/components/FileListTable.jsx:35 msgid "" -"Any assets in the Cloudflare cache that match the URL(s) exactly will be " -"purged from the cache." +"No files collected yet. Enable caching or an optimization, visit your site, " +"then choose \"Update files list\"." +msgstr "" + +#: assets/admin/app/components/FileListTable.jsx:75 +msgid "File" +msgstr "Datoteka" + +#: assets/admin/app/components/FileListTable.jsx:76 +#: assets/admin/app/tabs/CloudflareTab.jsx:113 +#: assets/admin/app/tabs/HtmlTab.jsx:45 +msgid "Minify" +msgstr "Umanji" + +#: assets/admin/app/components/FileListTable.jsx:77 +msgid "Inline" +msgstr "Umetni" + +#: assets/admin/app/components/FileListTable.jsx:78 +msgid "Combine" +msgstr "Kombinirati" + +#: assets/admin/app/components/FileListTable.jsx:79 +msgid "Disable" +msgstr "Onesposobiti" + +#: assets/admin/app/components/FileListTable.jsx:84 +msgid "Apply to all" msgstr "" -#: includes/addons/cloudflare/views/admin.php:70 includes/admin/cache.php:380 -#: includes/admin/css.php:351 includes/admin/includes/external_files.php:113 -#: includes/admin/includes/external_files.php:124 -#: includes/admin/includes/local_files.php:109 -#: includes/admin/includes/local_files.php:120 -#: includes/admin/javascript.php:277 includes/admin/media.php:180 -#: includes/admin/media.php:282 includes/functions/miscellaneous.php:260 +#: assets/admin/app/components/FileListTable.jsx:125 +#: assets/admin/app/components/FileListTable.jsx:132 +#: assets/admin/app/tabs/CacheTab.jsx:89 +#: assets/admin/app/tabs/CloudflareTab.jsx:90 +#: assets/admin/app/tabs/CssTab.jsx:160 assets/admin/app/tabs/HtmlTab.jsx:26 +#: assets/admin/app/tabs/JsTab.jsx:96 assets/admin/app/tabs/MediaTab.jsx:160 +#: assets/admin/app/tabs/MediaTab.jsx:177 msgid "Add URL" msgstr "Dodaj URL" -#: includes/addons/cloudflare/views/admin.php:78 -msgid "Development mode" -msgstr "Uključi development mode" - -#: includes/addons/cloudflare/views/admin.php:85 -msgid "Temporarily activate development mode on your website." -msgstr "Privremeno uključuje development mode na stranici" +#: assets/admin/app/components/ImageSizes.jsx:35 +msgid "Image size added." +msgstr "" -#: includes/addons/cloudflare/views/admin.php:86 -msgid "This setting will automatically turn off after 3 hours." -msgstr "Ova opcija će se automatski isključiti nakon 3 sata" +#: assets/admin/app/components/ImageSizes.jsx:37 +msgid "Could not add size." +msgstr "" -#: includes/addons/cloudflare/views/admin.php:91 -msgid "Cache level" -msgstr "Level predmemorija" +#: assets/admin/app/components/ImageSizes.jsx:43 +msgid "Remove this image size?" +msgstr "" -#: includes/addons/cloudflare/views/admin.php:94 -msgid "Aggressive - Standard" -msgstr "Agresivno - Standardno" +#: assets/admin/app/components/ImageSizes.jsx:49 +msgid "Could not remove size." +msgstr "" -#: includes/addons/cloudflare/views/admin.php:95 -msgid "Simplified - Ignore query string" -msgstr "Pojednostavljeno" +#: assets/admin/app/components/ImageSizes.jsx:55 +msgid "Restore default image sizes?" +msgstr "" -#: includes/addons/cloudflare/views/admin.php:96 -msgid "Basic - No query string" -msgstr "Osnovno" +#: assets/admin/app/components/ImageSizes.jsx:59 +msgid "Defaults restored." +msgstr "" -#: includes/addons/cloudflare/views/admin.php:101 -msgid "" -"Aggressive: Delivers a different resource each time the query string changes." +#: assets/admin/app/components/ImageSizes.jsx:64 +msgid "Regenerate all thumbnails? This may take a while." msgstr "" -"Agresivno: isporučuje drugi resurs svaki put kad se niz upita promijeni." -#: includes/addons/cloudflare/views/admin.php:102 -msgid "" -"Simplified: Delivers the same resource to everyone independent of the query " -"string." -msgstr "Pojednostavljeno: donosi isti resurs svima neovisno o nizu upita." +#: assets/admin/app/components/ImageSizes.jsx:81 +msgid "Thumbnails regenerated." +msgstr "" -#: includes/addons/cloudflare/views/admin.php:103 -msgid "" -"Basic: Only delivers resources from cache when there is no query string." -msgstr "Osnovno: isporučuje samo resurse iz predmemorije kada nema niza upita." +#: assets/admin/app/components/ImageSizes.jsx:83 +msgid "Regeneration failed." +msgstr "" -#: includes/addons/cloudflare/views/admin.php:118 -msgid "Browser Cache Expiration" -msgstr "Istek predmemorije preglednika" +#: assets/admin/app/components/ImageSizes.jsx:96 +msgid "Name" +msgstr "Naziv" -#: includes/addons/cloudflare/views/admin.php:121 -msgid "Respect Existing Headers" -msgstr "Poštuj postojeća zaglavlja" +#: assets/admin/app/components/ImageSizes.jsx:97 +msgid "W" +msgstr "" -#: includes/addons/cloudflare/views/admin.php:131 -msgid "" -"Browser cache TTL (in seconds) specifies how long CloudFlare-cached " -"resources will remain on your visitors computers." +#: assets/admin/app/components/ImageSizes.jsx:98 +msgid "H" msgstr "" -"Predmemorija preglednika TTL (u sekundama) određuje koliko dugo će resursi " -"spremljeni u CloudFlareu ostati na računalima posjetitelja." -#: includes/addons/cloudflare/views/admin.php:132 -msgid "The minimum TTL available depends on the plan level of the zone." -msgstr "Minimalna dostupnost TTL-a ovisi o planu zone koji koristite." +#: assets/admin/app/components/ImageSizes.jsx:99 +#: assets/admin/app/components/ImageSizes.jsx:153 +msgid "Crop" +msgstr "Izreži" + +#: assets/admin/app/components/ImageSizes.jsx:109 +msgid "Yes" +msgstr "Da" -#: includes/addons/cloudflare/views/admin.php:140 -msgid "Content" -msgstr "Sadržaj" +#: assets/admin/app/components/ImageSizes.jsx:129 +msgid "name" +msgstr "" -#: includes/addons/cloudflare/views/admin.php:146 includes/admin/css.php:27 -#: includes/admin/includes/local_files.php:153 includes/admin/javascript.php:27 -msgid "Minify" -msgstr "Umanji" +#: assets/admin/app/components/ImageSizes.jsx:159 +msgid "Cancel" +msgstr "" -#: includes/addons/cloudflare/views/admin.php:171 -msgid "Rocket Loader" -msgstr "Rocket Loader" +#: assets/admin/app/components/ImageSizes.jsx:165 +msgid "Add size" +msgstr "Dodaj veličinu" -#: includes/addons/cloudflare/views/admin.php:178 -msgid "Rocket Loader is a asynchronous JavaScript loader." -msgstr "Rocket Loader je asinkroni JavaScript loader." +#: assets/admin/app/components/ImageSizes.jsx:168 +msgid "Restore defaults" +msgstr "" -#: includes/addons/cloudflare/views/admin.php:183 -msgid "Brotli" -msgstr "Brotli" +#: assets/admin/app/components/ImageSizes.jsx:176 +msgid "Regenerating" +msgstr "" -#: includes/addons/cloudflare/views/admin.php:190 -msgid "" -"Speed up page load times for your visitor’s HTTPS traffic by applying Brotli " -"compression." +#: assets/admin/app/components/ImageSizes.jsx:177 +msgid "Regenerate thumbnails" +msgstr "Regenerirajte umanjene slike" + +#: assets/admin/app/components/SaveButton.jsx:12 +msgid "Saving…" msgstr "" -"Ubrzajte vrijeme učitavanja stranice za HTTPS promet posjetitelja primjenom " -"Brotli kompresije." -#: includes/addons/cloudflare/views/admin.php:198 includes/admin/addons.php:17 -#: includes/admin/cache.php:259 includes/admin/cdn.php:33 -#: includes/admin/css.php:119 includes/admin/database.php:183 -#: includes/admin/javascript.php:118 includes/admin/media.php:292 -#: includes/admin/settings.php:81 +#: assets/admin/app/components/SaveButton.jsx:12 msgid "Save changes" msgstr "Spremi izmjene" -#: includes/addons/cloudflare/views/admin.php:207 -msgid "Cloudflare credentials" -msgstr "Cloudflare podaci" +#: assets/admin/app/hooks/useSettingsGroup.js:46 +msgid "Settings saved." +msgstr "" -#: includes/addons/cloudflare/views/admin.php:211 -msgid "API key" -msgstr "API ključ" +#: assets/admin/app/hooks/useSettingsGroup.js:49 +msgid "Could not save settings." +msgstr "" -#: includes/addons/cloudflare/views/admin.php:218 -msgid "Account email" -msgstr "E-pošta računa" +#: assets/admin/app/lib/format.js:6 +msgid "just now" +msgstr "" -#: includes/addons/cloudflare/views/admin.php:223 -msgid "Zone ID" -msgstr "ID Zone" +#. translators: %d: number of minutes. +#: assets/admin/app/lib/format.js:11 +msgid "%d minute ago" +msgid_plural "%d minutes ago" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" + +#. translators: %d: number of hours. +#: assets/admin/app/lib/format.js:16 +msgid "%d hour ago" +msgid_plural "%d hours ago" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" + +#. translators: %d: number of days. +#: assets/admin/app/lib/format.js:20 +msgid "%d day ago" +msgid_plural "%d days ago" +msgstr[0] "" +msgstr[1] "" +msgstr[2] "" + +#: assets/admin/app/tabs/AddonsTab.jsx:39 +msgid "" +"Integrate your Cloudflare account to purge cache and manage zone settings." +msgstr "" -#: includes/addons/prefetch/views/addon.php:9 -#: includes/addons/prefetch/views/addon.php:18 -msgid "Dynamic page preload" -msgstr "Dinamičko pred učitavanje stranice" +#: assets/admin/app/tabs/AddonsTab.jsx:43 +msgid "Configure Cloudflare" +msgstr "" -#: includes/addons/prefetch/views/addon.php:12 -msgid "Preloads a page right before a user clicks on link" -msgstr "Dinamički pred učitava stranice prije nego ih korisnik posjeti" +#: assets/admin/app/tabs/AddonsTab.jsx:50 +#: assets/admin/app/tabs/SettingsTab.jsx:24 +msgid "Varnish" +msgstr "Varnish" -#: includes/addons/varnish/views/addon.php:20 -msgid "If Varnish runs on your server, you must activate this add-on." +#: assets/admin/app/tabs/AddonsTab.jsx:54 +msgid "Automatically purge Varnish whenever the cache is cleared." msgstr "" -"Ako je Varnish instaliran na vašem poslužitelju, morate aktivirati ovu " -"opciju." -#: includes/addons/varnish/views/addon.php:28 +#: assets/admin/app/tabs/AddonsTab.jsx:58 msgid "Custom host" msgstr "Prilagođeni URL host" -#: includes/addons/varnish/views/addon.php:41 -msgid "If you are using proxy, you may need this option" -msgstr "Ako koristite proxy, možda vam zatreba ova opcija" +#: assets/admin/app/tabs/AddonsTab.jsx:70 +msgid "Dynamic page prefetch" +msgstr "" -#: includes/admin/addons.php:27 includes/admin/admin.php:30 -#: includes/admin/admin.php:45 includes/functions/admin.php:236 -#: includes/functions/admin.php:240 -msgid "Add-ons" -msgstr "Dodaci" +#: assets/admin/app/tabs/AddonsTab.jsx:74 +msgid "Prefetch a page as soon as a visitor hovers over its link." +msgstr "" -#: includes/admin/addons.php:31 -#, php-format -msgid "Add more features to %s with add-ons." -msgstr "Dodajte više mogućnosti %s s dodacima" +#: assets/admin/app/tabs/CacheTab.jsx:19 +msgid "Minutes" +msgstr "" -#: includes/admin/admin.php:23 includes/admin/admin.php:38 -#: includes/functions/admin.php:166 -msgid "Cache" -msgstr "Predmemorija" +#: assets/admin/app/tabs/CacheTab.jsx:20 +msgid "Hours" +msgstr "" -#: includes/admin/admin.php:26 includes/admin/admin.php:41 -#: includes/functions/admin.php:196 includes/functions/admin.php:200 -msgid "Media" -msgstr "Media" +#: assets/admin/app/tabs/CacheTab.jsx:21 +msgid "Days" +msgstr "" -#: includes/admin/admin.php:27 includes/admin/admin.php:42 -#: includes/functions/admin.php:206 includes/functions/admin.php:210 -msgid "Database" -msgstr "Baza podataka" +#: assets/admin/app/tabs/CacheTab.jsx:24 assets/admin/app/tabs/HtmlTab.jsx:11 +msgid "" +"Use {numbers}, {letters}, {any} or {all} to match dynamic parts of a URL." +msgstr "" -#: includes/admin/admin.php:29 includes/admin/admin.php:44 -#: includes/admin/settings.php:12 includes/functions/admin.php:170 -#: includes/functions/admin.php:226 includes/functions/admin.php:230 -#: includes/functions/admin.php:290 -msgid "Settings" -msgstr "Postavke" +#: assets/admin/app/tabs/CacheTab.jsx:45 +#: assets/admin/app/tabs/OverviewTab.jsx:59 +msgid "Cache cleared." +msgstr "" + +#: assets/admin/app/tabs/CacheTab.jsx:47 +#: assets/admin/app/tabs/OverviewTab.jsx:61 +msgid "Could not clear the cache." +msgstr "" + +#: assets/admin/app/tabs/CacheTab.jsx:54 +msgid "HTML files" +msgstr "HTML datoteke" + +#: assets/admin/app/tabs/CacheTab.jsx:55 +msgid "CSS files" +msgstr "CSS datoteke" -#: includes/admin/cache.php:11 +#: assets/admin/app/tabs/CacheTab.jsx:56 +msgid "JavaScript files" +msgstr "JavaScript datoteke" + +#: assets/admin/app/tabs/CacheTab.jsx:61 +msgid "Cache statistics" +msgstr "Statistika predmemorije" + +#: assets/admin/app/tabs/CacheTab.jsx:70 +msgid "Total" +msgstr "" + +#: assets/admin/app/tabs/CacheTab.jsx:80 +#: assets/admin/app/tabs/OverviewTab.jsx:118 +msgid "Clearing…" +msgstr "" + +#: assets/admin/app/tabs/CacheTab.jsx:80 +#: assets/admin/app/tabs/OverviewTab.jsx:118 +msgid "Clear cache" +msgstr "Očisti predmemeoriju" + +#: assets/admin/app/tabs/CacheTab.jsx:84 +msgid "Exclude URL(s) from cache" +msgstr "Izuzimanje URL-ova iz predmemorije" + +#: assets/admin/app/tabs/CacheTab.jsx:94 +msgid "Exclude User Agent(s) from cache" +msgstr "Izuzmite korisničke agente iz predmemorije" + +#: assets/admin/app/tabs/CacheTab.jsx:98 +msgid "Add User Agent" +msgstr "Dodaj korisničkog agenta" + +#: assets/admin/app/tabs/CacheTab.jsx:104 +msgid "Exclude search engines" +msgstr "Izuzmi tražilice" + +#: assets/admin/app/tabs/CacheTab.jsx:105 +msgid "Google, Bing and other crawlers bypass the cache." +msgstr "" + +#: assets/admin/app/tabs/CacheTab.jsx:115 msgid "Enable cache" msgstr "Omogući predmemoriju" -#: includes/admin/cache.php:15 -msgid "Reduces your server response time by serving static files to users" +#: assets/admin/app/tabs/CacheTab.jsx:119 +msgid "Reduces server response time by serving static HTML files to visitors." msgstr "" -"Smanjuje vrijeme odgovora poslužitelja posluživanjem statičkih datoteka " -"korisnicima" -#: includes/admin/cache.php:30 includes/admin/cache.php:194 -#: includes/admin/cache.php:246 -msgid "" -"Your web site is running on a Nginx server and some additional steps may be " -"required in order to use this option." +#: assets/admin/app/tabs/CacheTab.jsx:128 +msgid "Mobile cache" msgstr "" -"Vaša web stranica se nalazi na Nginx poslužitelju i možda će biti potrebni " -"dodatni koraci kako bi se koristila ova opcija." -#: includes/admin/cache.php:39 +#: assets/admin/app/tabs/CacheTab.jsx:132 msgid "Separate cache for mobile devices" msgstr "Odvojite predmemoriju za mobilne uređaje" -#: includes/admin/cache.php:42 -msgid "Create a dedicated cache file for mobile devices" -msgstr "Spremite predmemoriju u zasebnu datoteku za mobilne uređaje" - -#: includes/admin/cache.php:48 +#: assets/admin/app/tabs/CacheTab.jsx:136 msgid "Clear cache after" msgstr "Očisti predmemoriju nakon" -#: includes/admin/cache.php:53 -msgid "minutes" -msgstr "minuta" +#: assets/admin/app/tabs/CacheTab.jsx:151 +msgid "Clear cache when" +msgstr "Očisti predmemoriju kada" + +#: assets/admin/app/tabs/CacheTab.jsx:155 +msgid "A post or page is published or updated" +msgstr "" + +#: assets/admin/app/tabs/CacheTab.jsx:160 +msgid "A post or page is deleted" +msgstr "Stranica ili post je izbrisan" + +#: assets/admin/app/tabs/CacheTab.jsx:165 +msgid "WP Performance settings are saved" +msgstr "" + +#: assets/admin/app/tabs/CacheTab.jsx:169 +msgid "Clear cache options" +msgstr "" + +#: assets/admin/app/tabs/CacheTab.jsx:173 +msgid "Keep generated CSS/JS files when clearing the cache" +msgstr "" + +#: assets/admin/app/tabs/CacheTab.jsx:177 +msgid "Query strings" +msgstr "" + +#: assets/admin/app/tabs/CacheTab.jsx:181 +msgid "Cache URLs with query strings" +msgstr "" + +#: assets/admin/app/tabs/CacheTab.jsx:182 +msgid "" +"Off (recommended): tracking params (utm, gclid, fbclid…) are ignored so only " +"clean URLs are cached." +msgstr "" + +#: assets/admin/app/tabs/CacheTab.jsx:190 +msgid "Cache preloading" +msgstr "Predučitavanje predmemorije" + +#: assets/admin/app/tabs/CacheTab.jsx:191 +msgid "Enter the path to an XML sitemap used to preload the cache." +msgstr "" + +#: assets/admin/app/tabs/CacheTab.jsx:200 +msgid "Add Sitemap" +msgstr "Dodaj XML mapu stranice" + +#: assets/admin/app/tabs/CacheTab.jsx:208 +msgid "Leverage browser caching" +msgstr "Iskoristite predmemoriju preglednika" + +#: assets/admin/app/tabs/CacheTab.jsx:212 +msgid "" +"Sets HTTP expiry headers so returning visitors load resources from their " +"browser." +msgstr "" + +#: assets/admin/app/tabs/CacheTab.jsx:218 +msgid "Gzip compression" +msgstr "" + +#: assets/admin/app/tabs/CacheTab.jsx:222 +msgid "Compresses resources before sending them to the browser." +msgstr "" + +#: assets/admin/app/tabs/CdnTab.jsx:18 +msgid "Exclude file(s) from CDN" +msgstr "Izuzmi datoteke iz CDN-a" + +#: assets/admin/app/tabs/CdnTab.jsx:23 assets/admin/app/tabs/CssTab.jsx:91 +#: assets/admin/app/tabs/JsTab.jsx:56 +msgid "Add file" +msgstr "Dodaj datoteku" + +#: assets/admin/app/tabs/CdnTab.jsx:26 +msgid "Use {numbers}, {letters} or {any} to match dynamic parts of a URL." +msgstr "" + +#: assets/admin/app/tabs/CdnTab.jsx:34 +msgid "Enable CDN" +msgstr "Omogući CDN" + +#: assets/admin/app/tabs/CdnTab.jsx:38 +msgid "" +"Rewrites static asset URLs (CSS, JavaScript, images) to your CDN hostname." +msgstr "" + +#: assets/admin/app/tabs/CdnTab.jsx:46 +msgid "CDN hostname" +msgstr "Naziv CDN poslužitelja" + +#: assets/admin/app/tabs/CloudflareTab.jsx:16 +#: assets/admin/app/tabs/HtmlTab.jsx:54 +#: assets/admin/app/tabs/OverviewTab.jsx:35 +msgid "Aggressive" +msgstr "" + +#: assets/admin/app/tabs/CloudflareTab.jsx:17 +msgid "Simplified (ignore query string)" +msgstr "" + +#: assets/admin/app/tabs/CloudflareTab.jsx:18 +msgid "Basic (no query string)" +msgstr "" + +#: assets/admin/app/tabs/CloudflareTab.jsx:35 +msgid "complete." +msgstr "" + +#: assets/admin/app/tabs/CloudflareTab.jsx:37 +#: assets/admin/app/tabs/CloudflareTab.jsx:40 +msgid "Cloudflare error." +msgstr "" + +#: assets/admin/app/tabs/CloudflareTab.jsx:48 +msgid "Respect existing headers" +msgstr "" + +#: assets/admin/app/tabs/CloudflareTab.jsx:52 +msgid "Credentials" +msgstr "" + +#: assets/admin/app/tabs/CloudflareTab.jsx:53 +msgid "Account email" +msgstr "E-pošta računa" + +#: assets/admin/app/tabs/CloudflareTab.jsx:56 +msgid "API key" +msgstr "API ključ" + +#: assets/admin/app/tabs/CloudflareTab.jsx:59 +msgid "Zone ID" +msgstr "ID Zone" + +#: assets/admin/app/tabs/CloudflareTab.jsx:67 +msgid "Purge cache" +msgstr "" + +#: assets/admin/app/tabs/CloudflareTab.jsx:73 +#: assets/admin/app/tabs/CloudflareTab.jsx:75 +msgid "Purge everything" +msgstr "Očisti sve" + +#: assets/admin/app/tabs/CloudflareTab.jsx:75 +msgid "Purging…" +msgstr "" + +#: assets/admin/app/tabs/CloudflareTab.jsx:81 +#: assets/admin/app/tabs/CloudflareTab.jsx:83 +msgid "Purge custom URLs" +msgstr "" + +#: assets/admin/app/tabs/CloudflareTab.jsx:86 +msgid "Custom URLs to purge" +msgstr "" + +#: assets/admin/app/tabs/CloudflareTab.jsx:95 +msgid "Zone settings" +msgstr "" + +#: assets/admin/app/tabs/CloudflareTab.jsx:96 +msgid "Development mode" +msgstr "Uključi development mode" + +#: assets/admin/app/tabs/CloudflareTab.jsx:100 +msgid "Temporarily bypass the Cloudflare cache (auto-off after 3h)" +msgstr "" + +#: assets/admin/app/tabs/CloudflareTab.jsx:103 +msgid "Cache level" +msgstr "Level predmemorija" + +#: assets/admin/app/tabs/CloudflareTab.jsx:106 +msgid "Browser cache TTL" +msgstr "" + +#: assets/admin/app/tabs/CloudflareTab.jsx:118 +msgid "Rocket Loader" +msgstr "Rocket Loader" + +#: assets/admin/app/tabs/CloudflareTab.jsx:119 +msgid "Asynchronous JavaScript loading" +msgstr "" + +#: assets/admin/app/tabs/CloudflareTab.jsx:121 +msgid "Brotli" +msgstr "Brotli" + +#: assets/admin/app/tabs/CloudflareTab.jsx:122 +msgid "Brotli compression" +msgstr "" + +#: assets/admin/app/tabs/CssTab.jsx:19 +msgid "Default" +msgstr "" + +#: assets/admin/app/tabs/CssTab.jsx:41 assets/admin/app/tabs/JsTab.jsx:30 +msgid "File list updated." +msgstr "" + +#: assets/admin/app/tabs/CssTab.jsx:43 assets/admin/app/tabs/JsTab.jsx:32 +msgid "Could not update the file list." +msgstr "" + +#: assets/admin/app/tabs/CssTab.jsx:51 +msgid "CSS settings" +msgstr "CSS postavke" + +#: assets/admin/app/tabs/CssTab.jsx:52 +msgid "Minify inline CSS" +msgstr "Smanji umetnuti CSS" + +#: assets/admin/app/tabs/CssTab.jsx:55 +msgid "Remove unused CSS" +msgstr "" + +#: assets/admin/app/tabs/CssTab.jsx:59 +msgid "Inline only used CSS; load the rest async" +msgstr "" + +#: assets/admin/app/tabs/CssTab.jsx:60 +msgid "" +"Heuristic: keeps rules whose classes/ids appear on the page. The full CSS " +"still loads async as a fallback." +msgstr "" + +#: assets/admin/app/tabs/CssTab.jsx:68 +msgid "Used-CSS safelist" +msgstr "" + +#: assets/admin/app/tabs/CssTab.jsx:69 +msgid "Selectors to always keep, e.g. classes toggled by JavaScript." +msgstr "" + +#: assets/admin/app/tabs/CssTab.jsx:74 +msgid "Add selector" +msgstr "" + +#: assets/admin/app/tabs/CssTab.jsx:78 +msgid "Asynchronous CSS" +msgstr "" + +#: assets/admin/app/tabs/CssTab.jsx:82 +msgid "Load CSS without render-blocking" +msgstr "" + +#: assets/admin/app/tabs/CssTab.jsx:87 +msgid "Exclude from async" +msgstr "" + +#: assets/admin/app/tabs/CssTab.jsx:95 +msgid "Critical CSS" +msgstr "" + +#: assets/admin/app/tabs/CssTab.jsx:96 +msgid "" +"Above-the-fold CSS, inlined and applied before the async stylesheet loads." +msgstr "" + +#: assets/admin/app/tabs/CssTab.jsx:107 +msgid "Google Fonts" +msgstr "" + +#: assets/admin/app/tabs/CssTab.jsx:111 +msgid "Combine Google Fonts into one request" +msgstr "" + +#: assets/admin/app/tabs/CssTab.jsx:116 +msgid "Host Google Fonts locally and preload them" +msgstr "" + +#: assets/admin/app/tabs/CssTab.jsx:119 +msgid "Font display" +msgstr "" + +#: assets/admin/app/tabs/CssTab.jsx:126 assets/admin/app/tabs/JsTab.jsx:82 +msgid "Logged-in users" +msgstr "" + +#: assets/admin/app/tabs/CssTab.jsx:130 +msgid "Disable CSS optimization for logged-in users" +msgstr "Onemogućite CSS optimizaciju za prijavljene korisnike" + +#: assets/admin/app/tabs/CssTab.jsx:135 +msgid "Resource hints" +msgstr "" + +#: assets/admin/app/tabs/CssTab.jsx:137 +msgid "DNS prefetch" +msgstr "" + +#: assets/admin/app/tabs/CssTab.jsx:138 +msgid "Origins to resolve early, e.g. https://fonts.gstatic.com" +msgstr "" + +#: assets/admin/app/tabs/CssTab.jsx:143 assets/admin/app/tabs/CssTab.jsx:150 +msgid "Add origin" +msgstr "" + +#: assets/admin/app/tabs/CssTab.jsx:146 +msgid "Preconnect" +msgstr "" + +#: assets/admin/app/tabs/CssTab.jsx:155 +msgid "Exclude URL(s) from CSS optimization" +msgstr "Izuzimanje URL-ova iz CSS optimizacije" + +#: assets/admin/app/tabs/CssTab.jsx:177 assets/admin/app/tabs/JsTab.jsx:113 +msgid "Updating…" +msgstr "" + +#: assets/admin/app/tabs/CssTab.jsx:177 assets/admin/app/tabs/JsTab.jsx:113 +msgid "Update files list" +msgstr "Ažuriraj popis datoteka" + +#: assets/admin/app/tabs/DatabaseTab.jsx:14 +msgid "Not scheduled" +msgstr "Nije zakazano" + +#: assets/admin/app/tabs/DatabaseTab.jsx:15 +msgid "Daily" +msgstr "Dnevno" + +#: assets/admin/app/tabs/DatabaseTab.jsx:16 +msgid "Weekly" +msgstr "Tjedno" + +#: assets/admin/app/tabs/DatabaseTab.jsx:17 +msgid "Monthly" +msgstr "Mjesečno" + +#: assets/admin/app/tabs/DatabaseTab.jsx:21 +msgid "Trash" +msgstr "Smeće" + +#: assets/admin/app/tabs/DatabaseTab.jsx:21 +msgid "Trashed posts and pages." +msgstr "" + +#: assets/admin/app/tabs/DatabaseTab.jsx:22 +msgid "Spam" +msgstr "Spam" + +#: assets/admin/app/tabs/DatabaseTab.jsx:22 +msgid "Spam and trashed comments." +msgstr "" + +#: assets/admin/app/tabs/DatabaseTab.jsx:23 +msgid "Revisions" +msgstr "Revizije" + +#: assets/admin/app/tabs/DatabaseTab.jsx:23 +msgid "Stored post revisions." +msgstr "" + +#: assets/admin/app/tabs/DatabaseTab.jsx:24 +msgid "Transients" +msgstr "Privremene postavke" + +#: assets/admin/app/tabs/DatabaseTab.jsx:24 +msgid "Expired and stale transients." +msgstr "" + +#: assets/admin/app/tabs/DatabaseTab.jsx:25 +msgid "Auto Drafts" +msgstr "Skice" + +#: assets/admin/app/tabs/DatabaseTab.jsx:25 +msgid "Auto-saved draft posts." +msgstr "" + +#: assets/admin/app/tabs/DatabaseTab.jsx:26 +msgid "Scheduled tasks" +msgstr "Zakazani zadaci" + +#: assets/admin/app/tabs/DatabaseTab.jsx:26 +msgid "Orphaned cron events." +msgstr "" + +#: assets/admin/app/tabs/DatabaseTab.jsx:51 +msgid "Back up your database first. Run this cleanup now?" +msgstr "" + +#: assets/admin/app/tabs/DatabaseTab.jsx:59 +msgid "Cleanup complete." +msgstr "" + +#: assets/admin/app/tabs/DatabaseTab.jsx:61 +msgid "Cleanup failed." +msgstr "" + +#: assets/admin/app/tabs/DatabaseTab.jsx:70 +msgid "Automatic database cleanup" +msgstr "Automatsko čišćenje baze podataka" + +#: assets/admin/app/tabs/DatabaseTab.jsx:71 +msgid "Schedule" +msgstr "Raspored" + +#: assets/admin/app/tabs/DatabaseTab.jsx:78 +msgid "Next run" +msgstr "Sljedeće čišćenje" + +#: assets/admin/app/tabs/DatabaseTab.jsx:82 +msgid "Not set" +msgstr "Nije postavljeno" + +#: assets/admin/app/tabs/DatabaseTab.jsx:103 +#: assets/admin/app/tabs/DatabaseTab.jsx:133 +msgid "Cleaning…" +msgstr "" + +#: assets/admin/app/tabs/DatabaseTab.jsx:103 +msgid "Delete" +msgstr "Izbriši" + +#: assets/admin/app/tabs/DatabaseTab.jsx:112 +msgid "Enable automatic cleanup" +msgstr "Omogući automatsko čišćenje" + +#: assets/admin/app/tabs/DatabaseTab.jsx:121 +msgid "" +"Back up your database before running any cleanup. These actions cannot be " +"undone." +msgstr "" + +#: assets/admin/app/tabs/DatabaseTab.jsx:134 +msgid "Delete all" +msgstr "Izbrisati sve" + +#: assets/admin/app/tabs/HtmlTab.jsx:21 +msgid "Exclude URL(s) from HTML optimization" +msgstr "" + +#: assets/admin/app/tabs/HtmlTab.jsx:35 +msgid "HTML optimization" +msgstr "" + +#: assets/admin/app/tabs/HtmlTab.jsx:39 +msgid "Enable HTML optimization" +msgstr "" + +#: assets/admin/app/tabs/HtmlTab.jsx:49 +msgid "Normal" +msgstr "" + +#: assets/admin/app/tabs/HtmlTab.jsx:58 +msgid "Remove comments" +msgstr "" + +#: assets/admin/app/tabs/HtmlTab.jsx:62 +msgid "Remove HTML comments (conditional comments preserved)" +msgstr "" + +#: assets/admin/app/tabs/HtmlTab.jsx:66 +msgid "Remove type attribute" +msgstr "" + +#: assets/admin/app/tabs/HtmlTab.jsx:70 +msgid "Remove type=\"text/css\" from link tags" +msgstr "" + +#: assets/admin/app/tabs/HtmlTab.jsx:75 +msgid "Remove type=\"text/javascript\" from script tags" +msgstr "" + +#: assets/admin/app/tabs/HtmlTab.jsx:79 +msgid "Remove quotes" +msgstr "" + +#: assets/admin/app/tabs/HtmlTab.jsx:83 +msgid "Remove quotes from attributes where possible" +msgstr "" + +#: assets/admin/app/tabs/JsTab.jsx:40 +msgid "JavaScript settings" +msgstr "JavaScript postavke" + +#: assets/admin/app/tabs/JsTab.jsx:41 +msgid "Minify inline JavaScript" +msgstr "Smanjite umetnuti JavaScript" + +#: assets/admin/app/tabs/JsTab.jsx:44 +msgid "Asynchronous JavaScript" +msgstr "" + +#: assets/admin/app/tabs/JsTab.jsx:48 +msgid "Defer JavaScript to remove render-blocking" +msgstr "" + +#: assets/admin/app/tabs/JsTab.jsx:52 +msgid "Exclude from defer" +msgstr "" + +#: assets/admin/app/tabs/JsTab.jsx:61 +msgid "Delay until interaction" +msgstr "" + +#: assets/admin/app/tabs/JsTab.jsx:65 +msgid "Delay JavaScript until user interaction" +msgstr "" + +#: assets/admin/app/tabs/JsTab.jsx:66 +msgid "" +"Biggest TBT/INP win: scripts run on first scroll, click, or key press. " +"Exclude anything that must run immediately." +msgstr "" + +#: assets/admin/app/tabs/JsTab.jsx:73 +msgid "Exclude from delay" +msgstr "" + +#: assets/admin/app/tabs/JsTab.jsx:86 +msgid "Disable JavaScript optimization for logged-in users" +msgstr "Onemogućite JavaScript optimizaciju za prijavljene korisnike" + +#: assets/admin/app/tabs/JsTab.jsx:91 +msgid "Exclude URL(s) from JavaScript optimization" +msgstr "Izuzimanje URL-ova iz JavaScript optimizacije" + +#: assets/admin/app/tabs/MediaTab.jsx:24 +msgid "Convert all images to WebP/AVIF? This can take a while." +msgstr "" + +#: assets/admin/app/tabs/MediaTab.jsx:38 +msgid "Images converted." +msgstr "" + +#: assets/admin/app/tabs/MediaTab.jsx:40 +msgid "Conversion failed." +msgstr "" + +#: assets/admin/app/tabs/MediaTab.jsx:48 +msgid "Emoji & Embeds" +msgstr "" + +#: assets/admin/app/tabs/MediaTab.jsx:49 +msgid "Emoji" +msgstr "" + +#: assets/admin/app/tabs/MediaTab.jsx:53 +msgid "Disable WordPress emoji" +msgstr "" + +#: assets/admin/app/tabs/MediaTab.jsx:56 +msgid "Embeds" +msgstr "Embeds" + +#: assets/admin/app/tabs/MediaTab.jsx:60 +msgid "Disable oEmbed discovery" +msgstr "" + +#: assets/admin/app/tabs/MediaTab.jsx:65 +msgid "Image sizes" +msgstr "Veličine slika" + +#: assets/admin/app/tabs/MediaTab.jsx:73 +msgid "Images" +msgstr "Slike" + +#: assets/admin/app/tabs/MediaTab.jsx:74 assets/admin/app/tabs/MediaTab.jsx:166 +msgid "Lazy load" +msgstr "Lazy load" + +#: assets/admin/app/tabs/MediaTab.jsx:78 +msgid "Lazy load images" +msgstr "Lazy load slika" + +#: assets/admin/app/tabs/MediaTab.jsx:79 +msgid "Defer offscreen images with native loading=\"lazy\"." +msgstr "" + +#: assets/admin/app/tabs/MediaTab.jsx:86 +msgid "Disable lazy load on mobile devices" +msgstr "Onemogući lazy load na mobilnim uređajima" + +#: assets/admin/app/tabs/MediaTab.jsx:91 +msgid "Responsive images" +msgstr "Responzivne slike" + +#: assets/admin/app/tabs/MediaTab.jsx:95 +msgid "Force srcset on images" +msgstr "" + +#: assets/admin/app/tabs/MediaTab.jsx:98 +msgid "Image dimensions" +msgstr "" + +#: assets/admin/app/tabs/MediaTab.jsx:102 +msgid "Add missing width/height to prevent layout shift (CLS)" +msgstr "" + +#: assets/admin/app/tabs/MediaTab.jsx:106 +msgid "Preload LCP images" +msgstr "" + +#: assets/admin/app/tabs/MediaTab.jsx:107 +msgid "" +"Number of above-the-fold images to preload (fetchpriority=high) and skip " +"from lazy load. 0 = off." +msgstr "" + +#: assets/admin/app/tabs/MediaTab.jsx:120 +msgid "Next-gen images" +msgstr "" + +#: assets/admin/app/tabs/MediaTab.jsx:121 +msgid "" +"Serve WebP/AVIF via when a converted file exists. New uploads " +"convert automatically." +msgstr "" + +#: assets/admin/app/tabs/MediaTab.jsx:126 +msgid "Serve WebP/AVIF images" +msgstr "" + +#: assets/admin/app/tabs/MediaTab.jsx:136 +msgid "Converting" +msgstr "" + +#: assets/admin/app/tabs/MediaTab.jsx:137 +msgid "Convert existing images" +msgstr "" + +#: assets/admin/app/tabs/MediaTab.jsx:141 +msgid "Exclude by name" +msgstr "" + +#: assets/admin/app/tabs/MediaTab.jsx:145 +msgid "Add image" +msgstr "" + +#: assets/admin/app/tabs/MediaTab.jsx:148 +msgid "Exclude containers" +msgstr "" + +#: assets/admin/app/tabs/MediaTab.jsx:148 +msgid "CSS id or class, e.g. #hero or .no-lazy" +msgstr "" + +#: assets/admin/app/tabs/MediaTab.jsx:152 +msgid "Add container" +msgstr "" + +#: assets/admin/app/tabs/MediaTab.jsx:155 +#: assets/admin/app/tabs/MediaTab.jsx:173 +msgid "Exclude URL(s)" +msgstr "Izuzmi URL" + +#: assets/admin/app/tabs/MediaTab.jsx:165 +msgid "Videos" +msgstr "Video" + +#: assets/admin/app/tabs/MediaTab.jsx:170 +msgid "Lazy load videos & iframes" +msgstr "" + +#: assets/admin/app/tabs/OverviewTab.jsx:18 +msgid "Safe" +msgstr "" + +#: assets/admin/app/tabs/OverviewTab.jsx:19 +msgid "" +"Page cache, GZIP, browser caching and lazy loading. Works with virtually any " +"theme." +msgstr "" + +#: assets/admin/app/tabs/OverviewTab.jsx:26 +msgid "Balanced" +msgstr "" + +#: assets/admin/app/tabs/OverviewTab.jsx:28 +msgid "" +"Adds deferred CSS/JS, hosted fonts and modern image formats. Recommended for " +"most sites." +msgstr "" + +#: assets/admin/app/tabs/OverviewTab.jsx:36 +msgid "" +"Every optimization on, including delayed JavaScript and unused-CSS removal. " +"Test your site after applying." +msgstr "" + +#: assets/admin/app/tabs/OverviewTab.jsx:68 +msgid "Apply this preset? It will overwrite the related settings." +msgstr "" + +#: assets/admin/app/tabs/OverviewTab.jsx:74 +msgid "Preset applied. Reloading…" +msgstr "" + +#: assets/admin/app/tabs/OverviewTab.jsx:77 +msgid "Could not apply the preset." +msgstr "" + +#: assets/admin/app/tabs/OverviewTab.jsx:90 +msgid "Cache status" +msgstr "" + +#: assets/admin/app/tabs/OverviewTab.jsx:94 +msgid "Active" +msgstr "" + +#: assets/admin/app/tabs/OverviewTab.jsx:95 +msgid "Disabled" +msgstr "" + +#: assets/admin/app/tabs/OverviewTab.jsx:100 +msgid "Cached pages" +msgstr "" + +#: assets/admin/app/tabs/OverviewTab.jsx:106 +msgid "Cache size" +msgstr "" + +#: assets/admin/app/tabs/OverviewTab.jsx:123 +msgid "Quick setup" +msgstr "" + +#: assets/admin/app/tabs/OverviewTab.jsx:125 +msgid "Apply a curated configuration in one click, then fine-tune any tab." +msgstr "" + +#: assets/admin/app/tabs/OverviewTab.jsx:137 +msgid "Recommended" +msgstr "" + +#: assets/admin/app/tabs/OverviewTab.jsx:149 +msgid "Applying…" +msgstr "" + +#: assets/admin/app/tabs/OverviewTab.jsx:150 +msgid "Apply" +msgstr "" + +#: assets/admin/app/tabs/OverviewTab.jsx:157 +msgid "Active optimizations" +msgstr "" + +#: assets/admin/app/tabs/OverviewTab.jsx:173 +msgid "Health checks" +msgstr "" + +#: assets/admin/app/tabs/Placeholder.jsx:8 +msgid "is being rebuilt in the next step." +msgstr "" + +#: assets/admin/app/tabs/SettingsTab.jsx:25 +msgid "Prefetch" +msgstr "" + +#: assets/admin/app/tabs/SettingsTab.jsx:60 +msgid "Log cleared." +msgstr "" + +#: assets/admin/app/tabs/SettingsTab.jsx:62 +msgid "Could not clear the log." +msgstr "" + +#: assets/admin/app/tabs/SettingsTab.jsx:67 +msgid "" +"Restore this saved configuration? Your current settings will be replaced." +msgstr "" + +#: assets/admin/app/tabs/SettingsTab.jsx:73 +msgid "Settings restored. Reloading…" +msgstr "" + +#: assets/admin/app/tabs/SettingsTab.jsx:76 +msgid "Could not restore settings." +msgstr "" + +#: assets/admin/app/tabs/SettingsTab.jsx:94 +msgid "Export failed." +msgstr "" + +#: assets/admin/app/tabs/SettingsTab.jsx:106 +msgid "Settings imported. Reloading…" +msgstr "" + +#: assets/admin/app/tabs/SettingsTab.jsx:109 +msgid "Import failed - invalid file." +msgstr "" + +#: assets/admin/app/tabs/SettingsTab.jsx:119 +msgid "Restore points" +msgstr "" + +#: assets/admin/app/tabs/SettingsTab.jsx:122 +msgid "" +"The last five saved configurations appear here so you can roll back a change." +msgstr "" + +#. translators: %s: settings group name. +#: assets/admin/app/tabs/SettingsTab.jsx:137 +msgid "%s settings" +msgstr "" + +#: assets/admin/app/tabs/SettingsTab.jsx:151 +msgid "Restoring…" +msgstr "" + +#: assets/admin/app/tabs/SettingsTab.jsx:152 +msgid "Restore" +msgstr "" -#: includes/admin/cache.php:56 -msgid "hours" -msgstr "sat" +#: assets/admin/app/tabs/SettingsTab.jsx:160 +msgid "About" +msgstr "" -#: includes/admin/cache.php:59 -msgid "days" -msgstr "dan" +#: assets/admin/app/tabs/SettingsTab.jsx:162 +msgid "" +"Export your configuration to move it between sites, or import a saved " +"configuration file." +msgstr "" -#: includes/admin/cache.php:66 -msgid "Clear cache when" -msgstr "Očisti predmemoriju kada" +#: assets/admin/app/tabs/SettingsTab.jsx:173 +msgid "Import / Export" +msgstr "" -#: includes/admin/cache.php:70 -msgid "A new post or page is published or updated" -msgstr "Nova stranica ili post je objavljen ili ažuriran" +#: assets/admin/app/tabs/SettingsTab.jsx:174 +msgid "Export settings" +msgstr "Izvezi postavke" -#: includes/admin/cache.php:75 -msgid "A post or page is deleted" -msgstr "Stranica ili post je izbrisan" +#: assets/admin/app/tabs/SettingsTab.jsx:176 +msgid "Download settings file" +msgstr "" -#: includes/admin/cache.php:80 -msgid "settings are saved" -msgstr "postavke su spremljene" +#: assets/admin/app/tabs/SettingsTab.jsx:179 +msgid "Import settings" +msgstr "Uvezi postavke" -#: includes/admin/cache.php:86 -msgid "Clear cache options" +#: assets/admin/app/tabs/SettingsTab.jsx:190 +msgid "Nginx rules" msgstr "" -#: includes/admin/cache.php:90 -msgid "Keep generated CSS/JS files" +#: assets/admin/app/tabs/SettingsTab.jsx:192 +msgid "Add these rules to your nginx server block, then reload nginx." msgstr "" -#: includes/admin/cache.php:96 -msgid "Cache preloading" -msgstr "Predučitavanje predmemorije" +#: assets/admin/app/tabs/SettingsTab.jsx:198 +msgid "Server" +msgstr "Poslužitelj" -#: includes/admin/cache.php:126 includes/admin/cache.php:136 -msgid "Enter path to XML sitemap which will be used for cache preloading" +#: assets/admin/app/tabs/SettingsTab.jsx:200 +msgid "Browser cache and gzip rules are written to .htaccess automatically." msgstr "" -"Unesite putanju do XML mape stranice koji će se koristiti za predučitavanje " -"predmemorije" - -#: includes/admin/cache.php:139 -msgid "Add Sitemap" -msgstr "Dodaj XML mapu stranice" -#: includes/admin/cache.php:147 -msgid "Browser caching" -msgstr "Predmemorija preglednika" +#: assets/admin/app/tabs/SettingsTab.jsx:207 +msgid "Redis object cache" +msgstr "" -#: includes/admin/cache.php:151 -msgid "Leverage browser caching" -msgstr "Iskoristite predmemoriju preglednika" +#: assets/admin/app/tabs/SettingsTab.jsx:211 +msgid "Enable persistent object cache" +msgstr "" -#: includes/admin/cache.php:176 +#: assets/admin/app/tabs/SettingsTab.jsx:212 msgid "" -"Setting an expiry date in the HTTP headers for static resources instructs " -"the browser to load previously downloaded resources from local disk rather " -"than over the network" +"Stores WordPress query and option lookups in Redis to cut database load. " +"Installs an object-cache.php drop-in." msgstr "" -"Postavljanje datuma isteka u HTTP zaglavljima za statičke resurse upućuje " -"preglednik na učitavanje prethodno preuzetih resursa s lokalnog diska, a ne " -"preko mreže" -#: includes/admin/cache.php:183 includes/admin/cache.php:235 +#: assets/admin/app/tabs/SettingsTab.jsx:220 msgid "" -"This option is turned ON automatically for all sites in Wordpress multisite" +"No supported object cache backend was detected. Install and enable the Redis " +"PHP extension to use a persistent object cache." msgstr "" -#: includes/admin/cache.php:204 -msgid "Enable gzip compression" -msgstr "Omogući gzip kompresiju" +#: assets/admin/app/tabs/SettingsTab.jsx:228 +msgid "Troubleshooting" +msgstr "" -#: includes/admin/cache.php:228 -msgid "" -"Compressing resources with gzip reduce the number of bytes sent over the " -"network" +#: assets/admin/app/tabs/SettingsTab.jsx:229 +msgid "Logging" msgstr "" -"Komprimiranje resursa pomoću gzip-a smanjuje broj bajtova poslanih preko " -"mreže" -#: includes/admin/cache.php:268 -msgid "Cache statistics" -msgstr "Statistika predmemorije" +#: assets/admin/app/tabs/SettingsTab.jsx:233 +msgid "Enable troubleshooting log" +msgstr "" -#: includes/admin/cache.php:269 includes/functions/admin.php:155 -#: includes/functions/admin.php:160 -msgid "Clear cache" -msgstr "Očisti predmemeoriju" +#: assets/admin/app/tabs/SettingsTab.jsx:234 +msgid "Records cache and optimization activity to help diagnose issues." +msgstr "" -#: includes/admin/cache.php:291 -msgid "HTML files" -msgstr "HTML datoteke" +#: assets/admin/app/tabs/SettingsTab.jsx:239 +msgid "Log file" +msgstr "" -#: includes/admin/cache.php:294 -msgid "CSS files" -msgstr "CSS datoteke" +#: assets/admin/app/tabs/SettingsTab.jsx:244 +msgid "The log is empty." +msgstr "" -#: includes/admin/cache.php:297 -msgid "JavaScript files" -msgstr "JavaScript datoteke" +#: assets/admin/app/tabs/SettingsTab.jsx:248 +msgid "Content refreshes automatically every 10 seconds." +msgstr "" -#: includes/admin/cache.php:302 -msgid "Total cache size" -msgstr "Ukupna veličina predmemorije" +#: assets/admin/app/tabs/SettingsTab.jsx:251 +msgid "Clear log" +msgstr "" -#: includes/admin/cache.php:313 -msgid "Exclude URL(s) from cache" -msgstr "Izuzimanje URL-ova iz predmemorije" +#, fuzzy +#~| msgid "Cloudflare credentials" +#~ msgid "Cloudflare - purge everything" +#~ msgstr "Cloudflare podaci" -#: includes/admin/cache.php:334 includes/admin/css.php:316 -#: includes/admin/javascript.php:242 includes/admin/media.php:135 -#: includes/admin/media.php:237 -#, php-format -msgid "Remove %s from excluded URL(s)?" -msgstr "Makni %s s liste izuzetih URL-ova" - -#: includes/admin/cache.php:365 includes/admin/cache.php:377 -#: includes/admin/cdn.php:75 includes/admin/cdn.php:86 -#: includes/admin/css.php:336 includes/admin/css.php:348 -#: includes/admin/javascript.php:262 includes/admin/javascript.php:274 -#: includes/admin/media.php:165 includes/admin/media.php:177 -#: includes/admin/media.php:267 includes/admin/media.php:279 -msgid "Use {numbers} to match only numbers" -msgstr "Koristite {numbers} za podudaranje samo brojeva" - -#: includes/admin/cache.php:366 includes/admin/cache.php:377 -#: includes/admin/cdn.php:76 includes/admin/cdn.php:86 -#: includes/admin/css.php:337 includes/admin/css.php:348 -#: includes/admin/javascript.php:263 includes/admin/javascript.php:274 -#: includes/admin/media.php:166 includes/admin/media.php:177 -#: includes/admin/media.php:268 includes/admin/media.php:279 -msgid "Use {letters} to match only letters" -msgstr "Koristite {letters} za podudaranje samo slova" - -#: includes/admin/cache.php:367 includes/admin/cache.php:377 -#: includes/admin/cdn.php:77 includes/admin/cdn.php:86 -#: includes/admin/css.php:338 includes/admin/css.php:348 -#: includes/admin/javascript.php:264 includes/admin/javascript.php:274 -#: includes/admin/media.php:167 includes/admin/media.php:177 -#: includes/admin/media.php:269 includes/admin/media.php:279 -msgid "Use {any} to match any string" -msgstr "Koristite {any} za podudaranje bilo kojeg niza" - -#: includes/admin/cache.php:368 includes/admin/cache.php:377 -#: includes/admin/css.php:339 includes/admin/css.php:348 -#: includes/admin/javascript.php:265 includes/admin/javascript.php:274 -#: includes/admin/media.php:168 includes/admin/media.php:177 -#: includes/admin/media.php:270 includes/admin/media.php:279 -msgid "Use {all} to match all" -msgstr "Koristite {all} za podudaranje bilo kojeg niza" - -#: includes/admin/cache.php:392 -msgid "Exclude User Agent(s) from cache" -msgstr "Izuzmite korisničke agente iz predmemorije" +#~ msgid "Cloudflare API credentials not set" +#~ msgstr "Cloudflare API podaci nisu postavljeni" -#: includes/admin/cache.php:427 -msgid "Add User Agent" -msgstr "Dodaj korisničkog agenta" +#~ msgid "" +#~ " Cloudflare cannot get zone details. Check your Cloudflare credentials" +#~ msgstr "" +#~ "Cloudflare ne može dobiti detalje zone. Provjerite Cloudflare podatke " +#~ "računa" -#: includes/admin/cache.php:437 -msgid "Exclude search engines" -msgstr "Izuzmi tražilice" +#, php-format +#~ msgid "" +#~ " Cloudflare zone %s is not activated. Please go to your Cloudflare " +#~ "dashboard and activate it." +#~ msgstr "" +#~ "Cloudflare zona %s nije aktivirana. Idite u svoju Cloudflare nadzornu " +#~ "ploču i aktivirajte je." -#: includes/admin/cdn.php:12 -msgid "Enable CDN" -msgstr "Omogući CDN" +#, php-format +#~ msgid "" +#~ " Cloudflare zone %s status is pending and these settings won't have any " +#~ "effect on your website." +#~ msgstr "" +#~ "Cloudflare zona %s je na čekanju i ove postavke neće imati nikakvog " +#~ "utjecaja na vašu web-lokaciju." -#: includes/admin/cdn.php:16 -msgid "" -"All URL(s) of static files ( CSS, JavaScript and Images ) will be rewritten " -"to the CDN hostname you provide. " -msgstr "" -"Svi URL-ovi statičkih datoteka (CSS, JavaScript i slike) bit će promijenjeni " -"u naziv CDN poslužitelja koji navedete." +#~ msgid " Cloudflare development mode not set" +#~ msgstr "Cloudflare razvojni mod nije postavljen" -#: includes/admin/cdn.php:23 -msgid "CDN hostname" -msgstr "Naziv CDN poslužitelja" +#~ msgid " Cloudflare cache level not set" +#~ msgstr "Cloudflare level predmemorije nije postavljen" -#: includes/admin/cdn.php:43 -msgid "Exclude file(s) from CDN" -msgstr "Izuzmi datoteke iz CDN-a" +#~ msgid " Cloudflare browser cache expiration not set" +#~ msgstr "Cloudflare istek predmemorije preglednika nije postavljen" -#: includes/admin/cdn.php:89 -msgid "Add file" -msgstr "Dodaj datoteku" +#~ msgid " Cloudflare minify not set" +#~ msgstr "Cloudflare minifikacija nije postavljena" -#: includes/admin/css.php:26 includes/admin/javascript.php:26 -msgid "File" -msgstr "Datoteka" +#~ msgid " Cloudflare Rocket loader mode not set" +#~ msgstr " Cloudflare Rocket loader mod nije postavljen" -#: includes/admin/css.php:28 includes/admin/includes/local_files.php:171 -#: includes/admin/javascript.php:28 -msgid "Inline" -msgstr "Umetni" +#~ msgid " Cloudflare Brotli mode not set" +#~ msgstr " Cloudflare Brotli mod nije postavljen" -#: includes/admin/css.php:29 includes/admin/includes/local_files.php:189 -#: includes/admin/javascript.php:29 -msgid "Combine" -msgstr "Kombinirati" +#~ msgid "Cloudflare settings saved" +#~ msgstr "Cloudflare postavke spremljene" -#: includes/admin/css.php:30 includes/admin/includes/external_files.php:152 -#: includes/admin/includes/local_files.php:213 includes/admin/javascript.php:30 -msgid "Disable" -msgstr "Onesposobiti" +#~ msgid "Integrate your Cloudflare account with this add-on." +#~ msgstr "S ovim dodatkom integrirajte svoj račun za Cloudflare." -#: includes/admin/css.php:37 includes/admin/javascript.php:37 -msgid "Update all files in list below" -msgstr "Ažurirajte sve datoteke na popisu u nastavku" +#~ msgid "Enable" +#~ msgstr "Omogući" -#: includes/admin/css.php:47 includes/admin/javascript.php:47 -msgid "Theme" -msgstr "Tema" +#~ msgid "Caching" +#~ msgstr "Predmemorija" -#: includes/admin/css.php:69 includes/admin/javascript.php:69 -msgid "Plugins" -msgstr "Dodatci" +#~ msgid "Purge Cache" +#~ msgstr "Očisti predmemoriju" -#: includes/admin/css.php:92 includes/admin/javascript.php:92 -msgid "External resources" -msgstr "Vanjski resursi" +#~ msgid "Clear all Cloudflare cache" +#~ msgstr "Očisti Cloudflare predmemoriju" -#: includes/admin/css.php:115 includes/admin/javascript.php:114 -msgid "" -"If some of the files are missing from this list, enable Cache preloading " -"option." -msgstr "" -"Ako neke datoteke nedostaju s ovog popisa, omogućite opciju Predučitavanje " -"predmemorije." +#~ msgid "Temporarily activate development mode on your website." +#~ msgstr "Privremeno uključuje development mode na stranici" -#: includes/admin/css.php:122 includes/admin/javascript.php:121 -#, php-format -msgid "Clear collected %s files list.%s This option will also clear the cache." -msgstr "" -"Izbriši popis prikupljanih %s datoteka.%s Ova opcija će također izbrisati i " -"predmemoriju." +#~ msgid "This setting will automatically turn off after 3 hours." +#~ msgstr "Ova opcija će se automatski isključiti nakon 3 sata" -#: includes/admin/css.php:125 includes/admin/javascript.php:124 -msgid "Update files list" -msgstr "Ažuriraj popis datoteka" +#~ msgid "Aggressive - Standard" +#~ msgstr "Agresivno - Standardno" -#: includes/admin/css.php:130 -msgid "CSS files not found" -msgstr "CSS datoteke nisu pronađene" +#~ msgid "Simplified - Ignore query string" +#~ msgstr "Pojednostavljeno" -#: includes/admin/css.php:134 includes/admin/javascript.php:133 -msgid "Reload" -msgstr "Ponovno učitati" +#~ msgid "Basic - No query string" +#~ msgstr "Osnovno" -#: includes/admin/css.php:142 -msgid "CSS settings" -msgstr "CSS postavke" +#~ msgid "" +#~ "Aggressive: Delivers a different resource each time the query string " +#~ "changes." +#~ msgstr "" +#~ "Agresivno: isporučuje drugi resurs svaki put kad se niz upita promijeni." -#: includes/admin/css.php:158 -msgid "Minify inline CSS" -msgstr "Smanji umetnuti CSS" +#~ msgid "" +#~ "Simplified: Delivers the same resource to everyone independent of the " +#~ "query string." +#~ msgstr "Pojednostavljeno: donosi isti resurs svima neovisno o nizu upita." -#: includes/admin/css.php:166 -msgid "Asynchronously load CSS" -msgstr "Asinhrono učitajte CSS" +#~ msgid "" +#~ "Basic: Only delivers resources from cache when there is no query string." +#~ msgstr "" +#~ "Osnovno: isporučuje samo resurse iz predmemorije kada nema niza upita." -#: includes/admin/css.php:176 includes/admin/css.php:178 -msgid "Show critical CSS" -msgstr "Prikaži CSS definicije" +#~ msgid "Browser Cache Expiration" +#~ msgstr "Istek predmemorije preglednika" -#: includes/admin/css.php:177 includes/admin/css.php:178 -msgid "Hide critical CSS" -msgstr "Sakri CSS definicije" +#~ msgid "Respect Existing Headers" +#~ msgstr "Poštuj postojeća zaglavlja" -#: includes/admin/css.php:188 -msgid "Eliminates render-blocking CSS" -msgstr "CSS se ne prikazuje kao blokirajući sadržaj" +#~ msgid "" +#~ "Browser cache TTL (in seconds) specifies how long CloudFlare-cached " +#~ "resources will remain on your visitors computers." +#~ msgstr "" +#~ "Predmemorija preglednika TTL (u sekundama) određuje koliko dugo će " +#~ "resursi spremljeni u CloudFlareu ostati na računalima posjetitelja." -#: includes/admin/css.php:194 -msgid "" -"Loading CSS asynchronously will produce FOUC effect (a Flash Of Unstyled " -"Content). In order to minimize the FOUC effect, use critical CSS path." -msgstr "" -"Učitavanje CSS-a asinkrono će rezultirati FOUC efektom (Flash Of Unstyled " -"Content). Kako bi se smanjio FOUC učinak, umetnite kritične CSS definicije." +#~ msgid "The minimum TTL available depends on the plan level of the zone." +#~ msgstr "Minimalna dostupnost TTL-a ovisi o planu zone koji koristite." -#: includes/admin/css.php:202 -msgid "Critical CSS path" -msgstr "Kritične CSS definicije" +#~ msgid "Content" +#~ msgstr "Sadržaj" -#: includes/admin/css.php:207 -msgid "Enter critical CSS path definitions" -msgstr "Unesi kritične CSS definicije" +#~ msgid "Rocket Loader is a asynchronous JavaScript loader." +#~ msgstr "Rocket Loader je asinkroni JavaScript loader." -#: includes/admin/css.php:212 -msgid "Generate critical CSS path" -msgstr "Generirajte kritične CSS definicije" +#~ msgid "" +#~ "Speed up page load times for your visitor’s HTTPS traffic by applying " +#~ "Brotli compression." +#~ msgstr "" +#~ "Ubrzajte vrijeme učitavanja stranice za HTTPS promet posjetitelja " +#~ "primjenom Brotli kompresije." -#: includes/admin/css.php:227 -msgid "Combine Google Fonts" -msgstr "Kombinirajte Google fontove" +#~ msgid "Cloudflare credentials" +#~ msgstr "Cloudflare podaci" -#: includes/admin/css.php:232 -msgid "Load all google fonts in one HTTP request" -msgstr "Učitajte sve Google fontove u jednom HTTP zahtjevu" +#~ msgid "Dynamic page preload" +#~ msgstr "Dinamičko pred učitavanje stranice" -#: includes/admin/css.php:241 -msgid "Disable CSS optimization for logged-in users" -msgstr "Onemogućite CSS optimizaciju za prijavljene korisnike" +#~ msgid "Preloads a page right before a user clicks on link" +#~ msgstr "Dinamički pred učitava stranice prije nego ih korisnik posjeti" -#: includes/admin/css.php:252 includes/admin/javascript.php:178 -msgid "Resource Hints" -msgstr "Postavke za vanjske resurse" +#~ msgid "If Varnish runs on your server, you must activate this add-on." +#~ msgstr "" +#~ "Ako je Varnish instaliran na vašem poslužitelju, morate aktivirati ovu " +#~ "opciju." -#: includes/admin/css.php:259 includes/admin/javascript.php:185 -msgid "Origins" -msgstr "Podrijetlo" +#~ msgid "If you are using proxy, you may need this option" +#~ msgstr "Ako koristite proxy, možda vam zatreba ova opcija" -#: includes/admin/css.php:286 includes/admin/javascript.php:212 -msgid "DNS prefetching can make external resources load faster" -msgstr "Prethodno dohvaćanje DNS-a može ubrzati učitavanje vanjskih resursa" +#, php-format +#~ msgid "Add more features to %s with add-ons." +#~ msgstr "Dodajte više mogućnosti %s s dodacima" -#: includes/admin/css.php:287 includes/admin/javascript.php:213 -msgid "Preconnect can remove additional roundtrips and reduce request latency" -msgstr "" -"Preconnect može ukloniti dodatne HTTP round-trip zahtjeve i tako smanjiti " -"latenciju HTTP zahtjeva" +#~ msgid "Reduces your server response time by serving static files to users" +#~ msgstr "" +#~ "Smanjuje vrijeme odgovora poslužitelja posluživanjem statičkih datoteka " +#~ "korisnicima" -#: includes/admin/css.php:295 -msgid "Exclude URL(s) from CSS optimization" -msgstr "Izuzimanje URL-ova iz CSS optimizacije" +#~ msgid "" +#~ "Your web site is running on a Nginx server and some additional steps may " +#~ "be required in order to use this option." +#~ msgstr "" +#~ "Vaša web stranica se nalazi na Nginx poslužitelju i možda će biti " +#~ "potrebni dodatni koraci kako bi se koristila ova opcija." -#: includes/admin/database.php:30 includes/admin/database.php:35 -msgid "Delete all pages, posts and comments from trash" -msgstr "Izbrišite sve stranice, postove i komentare iz smeća" +#~ msgid "Create a dedicated cache file for mobile devices" +#~ msgstr "Spremite predmemoriju u zasebnu datoteku za mobilne uređaje" -#: includes/admin/database.php:31 includes/admin/database.php:55 -#: includes/admin/database.php:82 includes/admin/database.php:105 -#: includes/admin/database.php:132 includes/admin/database.php:157 -msgid "Delete" -msgstr "Izbriši" +#~ msgid "minutes" +#~ msgstr "minuta" -#: includes/admin/database.php:34 -msgid "Trash" -msgstr "Smeće" +#~ msgid "hours" +#~ msgstr "sat" -#: includes/admin/database.php:41 includes/admin/database.php:65 -#: includes/admin/database.php:92 includes/admin/database.php:115 -#: includes/admin/database.php:142 includes/admin/database.php:167 -msgid "Enable automatic cleanup" -msgstr "Omogući automatsko čišćenje" +#~ msgid "days" +#~ msgstr "dan" -#: includes/admin/database.php:54 includes/admin/database.php:59 -msgid "Delete all spam comments" -msgstr "Izbrišite sve spam komentare" +#~ msgid "A new post or page is published or updated" +#~ msgstr "Nova stranica ili post je objavljen ili ažuriran" -#: includes/admin/database.php:58 -msgid "Spam" -msgstr "Spam" +#~ msgid "settings are saved" +#~ msgstr "postavke su spremljene" -#: includes/admin/database.php:81 includes/admin/database.php:86 -msgid "Delete all revisions" -msgstr "Izbrišite sve revizije" +#~ msgid "Enter path to XML sitemap which will be used for cache preloading" +#~ msgstr "" +#~ "Unesite putanju do XML mape stranice koji će se koristiti za " +#~ "predučitavanje predmemorije" -#: includes/admin/database.php:85 -msgid "Revisions" -msgstr "Revizije" +#~ msgid "" +#~ "Setting an expiry date in the HTTP headers for static resources instructs " +#~ "the browser to load previously downloaded resources from local disk " +#~ "rather than over the network" +#~ msgstr "" +#~ "Postavljanje datuma isteka u HTTP zaglavljima za statičke resurse upućuje " +#~ "preglednik na učitavanje prethodno preuzetih resursa s lokalnog diska, a " +#~ "ne preko mreže" -#: includes/admin/database.php:104 includes/admin/database.php:109 -msgid "Delete all expired transients" -msgstr "Izbrišite sve istekle privremene postavke" +#~ msgid "Enable gzip compression" +#~ msgstr "Omogući gzip kompresiju" -#: includes/admin/database.php:108 -msgid "Transients" -msgstr "Privremene postavke" +#~ msgid "" +#~ "Compressing resources with gzip reduce the number of bytes sent over the " +#~ "network" +#~ msgstr "" +#~ "Komprimiranje resursa pomoću gzip-a smanjuje broj bajtova poslanih preko " +#~ "mreže" -#: includes/admin/database.php:131 includes/admin/database.php:136 -msgid "Delete all auto drafts" -msgstr "Izbrišite sve skice" +#~ msgid "Total cache size" +#~ msgstr "Ukupna veličina predmemorije" -#: includes/admin/database.php:135 -msgid "Auto Drafts" -msgstr "Skice" +#, php-format +#~ msgid "Remove %s from excluded URL(s)?" +#~ msgstr "Makni %s s liste izuzetih URL-ova" -#: includes/admin/database.php:156 includes/admin/database.php:161 -msgid "Delete all unused scheduled tasks" -msgstr "Obrišite sve zakazane zadatke koji se ne koriste" +#~ msgid "Use {numbers} to match only numbers" +#~ msgstr "Koristite {numbers} za podudaranje samo brojeva" -#: includes/admin/database.php:160 -msgid "Scheduled tasks" -msgstr "Zakazani zadaci" +#~ msgid "Use {letters} to match only letters" +#~ msgstr "Koristite {letters} za podudaranje samo slova" -#: includes/admin/database.php:179 -msgid "" -"Backup your database before running any of these cleanup actions. Once a " -"database cleanup has been performed, there is no way to undo it." -msgstr "" -"Izradite sigurnosnu kopiju baze podataka prije pokretanja bilo koje od ovih " -"akcija čišćenja. Nakon što je već izvršeno čišćenje baze, nema načina da se " -"izmjene ponište i vrate podaci." +#~ msgid "Use {any} to match any string" +#~ msgstr "Koristite {any} za podudaranje bilo kojeg niza" -#: includes/admin/database.php:185 includes/admin/database.php:186 -msgid "Delete all" -msgstr "Izbrisati sve" +#~ msgid "Use {all} to match all" +#~ msgstr "Koristite {all} za podudaranje bilo kojeg niza" -#: includes/admin/database.php:194 -msgid "Automatic database cleanup" -msgstr "Automatsko čišćenje baze podataka" +#~ msgid "" +#~ "All URL(s) of static files ( CSS, JavaScript and Images ) will be " +#~ "rewritten to the CDN hostname you provide. " +#~ msgstr "" +#~ "Svi URL-ovi statičkih datoteka (CSS, JavaScript i slike) bit će " +#~ "promijenjeni u naziv CDN poslužitelja koji navedete." -#: includes/admin/database.php:200 -msgid "Schedule" -msgstr "Raspored" +#~ msgid "Update all files in list below" +#~ msgstr "Ažurirajte sve datoteke na popisu u nastavku" -#: includes/admin/database.php:202 -msgid "Not scheduled" -msgstr "Nije zakazano" +#~ msgid "External resources" +#~ msgstr "Vanjski resursi" -#: includes/admin/database.php:203 includes/functions/cron.php:26 -msgid "Daily" -msgstr "Dnevno" +#~ msgid "" +#~ "If some of the files are missing from this list, enable Cache preloading " +#~ "option." +#~ msgstr "" +#~ "Ako neke datoteke nedostaju s ovog popisa, omogućite opciju " +#~ "Predučitavanje predmemorije." -#: includes/admin/database.php:204 includes/functions/cron.php:31 -msgid "Weekly" -msgstr "Tjedno" +#, php-format +#~ msgid "" +#~ "Clear collected %s files list.%s This option will also clear the cache." +#~ msgstr "" +#~ "Izbriši popis prikupljanih %s datoteka.%s Ova opcija će također izbrisati " +#~ "i predmemoriju." -#: includes/admin/database.php:205 includes/functions/cron.php:36 -msgid "Monthly" -msgstr "Mjesečno" +#~ msgid "CSS files not found" +#~ msgstr "CSS datoteke nisu pronađene" -#: includes/admin/database.php:208 -msgid "Next run" -msgstr "Sljedeće čišćenje" +#~ msgid "Reload" +#~ msgstr "Ponovno učitati" -#: includes/admin/database.php:214 -msgid "Not set" -msgstr "Nije postavljeno" +#~ msgid "Asynchronously load CSS" +#~ msgstr "Asinhrono učitajte CSS" -#: includes/admin/includes/external_files.php:31 -#: includes/admin/includes/local_files.php:31 -#: includes/functions/miscellaneous.php:261 -msgid "Disable everywhere" -msgstr "Onemogućite svugdje" - -#: includes/admin/includes/external_files.php:35 -#: includes/admin/includes/local_files.php:35 -#: includes/functions/miscellaneous.php:262 -msgid "Disable only on selected URL" -msgstr "Onemogućite samo na odabranom URL-u" - -#: includes/admin/includes/external_files.php:39 -#: includes/admin/includes/local_files.php:39 -#: includes/functions/miscellaneous.php:263 -msgid "Disable everywhere except on selected URL" -msgstr "Onemogući svugdje osim na odabranom URL-u" - -#: includes/admin/javascript.php:129 -msgid "JavaScript files not found" -msgstr "JavaScript datoteke nisu pronađene" - -#: includes/admin/javascript.php:142 -msgid "JavaScript settings" -msgstr "JavaScript postavke" +#~ msgid "Show critical CSS" +#~ msgstr "Prikaži CSS definicije" -#: includes/admin/javascript.php:150 -msgid "Minify inline JavaScript" -msgstr "Smanjite umetnuti JavaScript" +#~ msgid "Hide critical CSS" +#~ msgstr "Sakri CSS definicije" -#: includes/admin/javascript.php:157 -msgid "Asynchronously load JavaScript" -msgstr "Asinhrono učitajte JavaScript" +#~ msgid "Eliminates render-blocking CSS" +#~ msgstr "CSS se ne prikazuje kao blokirajući sadržaj" -#: includes/admin/javascript.php:161 -msgid "Eliminates render-blocking JavaScript" -msgstr "JavaScript se ne prikazuje kao blokirajući sadržaj" +#~ msgid "" +#~ "Loading CSS asynchronously will produce FOUC effect (a Flash Of Unstyled " +#~ "Content). In order to minimize the FOUC effect, use critical CSS path." +#~ msgstr "" +#~ "Učitavanje CSS-a asinkrono će rezultirati FOUC efektom (Flash Of Unstyled " +#~ "Content). Kako bi se smanjio FOUC učinak, umetnite kritične CSS " +#~ "definicije." -#: includes/admin/javascript.php:167 -msgid "Disable JavaScript optimization for logged-in users" -msgstr "Onemogućite JavaScript optimizaciju za prijavljene korisnike" +#~ msgid "Critical CSS path" +#~ msgstr "Kritične CSS definicije" -#: includes/admin/javascript.php:221 -msgid "Exclude URL(s) from JavaScript optimization" -msgstr "Izuzimanje URL-ova iz JavaScript optimizacije" +#~ msgid "Enter critical CSS path definitions" +#~ msgstr "Unesi kritične CSS definicije" -#: includes/admin/media.php:12 -msgid "Images" -msgstr "Slike" +#~ msgid "Generate critical CSS path" +#~ msgstr "Generirajte kritične CSS definicije" -#: includes/admin/media.php:16 includes/admin/media.php:192 -msgid "Lazy load" -msgstr "Lazy load" +#~ msgid "Combine Google Fonts" +#~ msgstr "Kombinirajte Google fontove" -#: includes/admin/media.php:20 -msgid "Lazy load images" -msgstr "Lazy load slika" +#~ msgid "Load all google fonts in one HTTP request" +#~ msgstr "Učitajte sve Google fontove u jednom HTTP zahtjevu" -#: includes/admin/media.php:24 includes/admin/media.php:209 -msgid "Reduces the number of HTTP requests and improves loading time" -msgstr "Smanjuje broj HTTP zahtjeva i poboljšava vrijeme učitavanja stranice" +#~ msgid "Resource Hints" +#~ msgstr "Postavke za vanjske resurse" -#: includes/admin/media.php:34 -msgid "Disable lazy load on mobile devices" -msgstr "Onemogući lazy load na mobilnim uređajima" +#~ msgid "Origins" +#~ msgstr "Podrijetlo" -#: includes/admin/media.php:40 -msgid "Responsive images" -msgstr "Responzivne slike" +#~ msgid "DNS prefetching can make external resources load faster" +#~ msgstr "Prethodno dohvaćanje DNS-a može ubrzati učitavanje vanjskih resursa" -#: includes/admin/media.php:44 -msgid "Force images to use srcset attribute" -msgstr "Prisilite slike da koriste srcset atribut" +#~ msgid "" +#~ "Preconnect can remove additional roundtrips and reduce request latency" +#~ msgstr "" +#~ "Preconnect može ukloniti dodatne HTTP round-trip zahtjeve i tako smanjiti " +#~ "latenciju HTTP zahtjeva" -#: includes/admin/media.php:47 -msgid "" -"Loads the best optimized image depending on users screen size and image " -"sizes settings" -msgstr "" -"Učitava najbolju optimiziranu sliku ovisno o veličini zaslona i postavkama " -"veličine slike" +#~ msgid "Delete all pages, posts and comments from trash" +#~ msgstr "Izbrišite sve stranice, postove i komentare iz smeća" -#: includes/admin/media.php:52 -msgid "Exclude" -msgstr "Izuzmi" +#~ msgid "Delete all spam comments" +#~ msgstr "Izbrišite sve spam komentare" -#: includes/admin/media.php:55 -msgid "Exclude image by name" -msgstr "Izuzmi sliku po imenu slike" +#~ msgid "Delete all revisions" +#~ msgstr "Izbrišite sve revizije" -#: includes/admin/media.php:72 -msgid "Add Image" -msgstr "Dodaj sliku" +#~ msgid "Delete all expired transients" +#~ msgstr "Izbrišite sve istekle privremene postavke" -#: includes/admin/media.php:81 -msgid "" -"Exclude images located in specific html containers like sliders and galleries" -msgstr "" -"Izuzmite slike koje se nalaze u određenim html kontejnerima kao npr. galerije" +#~ msgid "Delete all auto drafts" +#~ msgstr "Izbrišite sve skice" -#: includes/admin/media.php:99 includes/admin/media.php:108 -msgid "Enter container id or class name" -msgstr "Unesite ID kontejnera ili naziv klase" +#~ msgid "Delete all unused scheduled tasks" +#~ msgstr "Obrišite sve zakazane zadatke koji se ne koriste" -#: includes/admin/media.php:100 includes/admin/media.php:108 -msgid "Example" -msgstr "Primjer" +#~ msgid "" +#~ "Backup your database before running any of these cleanup actions. Once a " +#~ "database cleanup has been performed, there is no way to undo it." +#~ msgstr "" +#~ "Izradite sigurnosnu kopiju baze podataka prije pokretanja bilo koje od " +#~ "ovih akcija čišćenja. Nakon što je već izvršeno čišćenje baze, nema " +#~ "načina da se izmjene ponište i vrate podaci." -#: includes/admin/media.php:108 -msgid "Add Container" -msgstr "Dodaj kontejner" +#~ msgid "Disable everywhere" +#~ msgstr "Onemogućite svugdje" -#: includes/admin/media.php:116 -msgid "Exclude URL(s) from image optimization" -msgstr "Izuzmi URL iz CSS optimizacije" +#~ msgid "Disable only on selected URL" +#~ msgstr "Onemogućite samo na odabranom URL-u" -#: includes/admin/media.php:188 -msgid "Videos" -msgstr "Video" +#~ msgid "Disable everywhere except on selected URL" +#~ msgstr "Onemogući svugdje osim na odabranom URL-u" -#: includes/admin/media.php:204 -msgid "Lazy load videos" -msgstr "Lazy load videa" +#~ msgid "JavaScript files not found" +#~ msgstr "JavaScript datoteke nisu pronađene" -#: includes/admin/media.php:218 -msgid "Exclude URL(s)" -msgstr "Izuzmi URL" +#~ msgid "Asynchronously load JavaScript" +#~ msgstr "Asinhrono učitajte JavaScript" -#: includes/admin/media.php:303 -msgid "Emoji" -msgstr "" +#~ msgid "Eliminates render-blocking JavaScript" +#~ msgstr "JavaScript se ne prikazuje kao blokirajući sadržaj" -#: includes/admin/media.php:310 -msgid "Disable Emoji" -msgstr "Onemogući Emoji" +#~ msgid "Reduces the number of HTTP requests and improves loading time" +#~ msgstr "" +#~ "Smanjuje broj HTTP zahtjeva i poboljšava vrijeme učitavanja stranice" -#: includes/admin/media.php:314 -msgid "" -"Use default emoji of visitor's browser instead of loading emoji from " -"WordPress.org" -msgstr "" -"Upotrijebite zadani emotikon preglednika posjetitelja umjesto učitavanja " -"emotikona sa WordPress.org" +#~ msgid "Force images to use srcset attribute" +#~ msgstr "Prisilite slike da koriste srcset atribut" -#: includes/admin/media.php:319 -msgid "Embeds" -msgstr "Embeds" +#~ msgid "" +#~ "Loads the best optimized image depending on users screen size and image " +#~ "sizes settings" +#~ msgstr "" +#~ "Učitava najbolju optimiziranu sliku ovisno o veličini zaslona i " +#~ "postavkama veličine slike" -#: includes/admin/media.php:326 -msgid "Disable embeds" -msgstr "Onemogući ugrađivanje (embeds)" +#~ msgid "Exclude" +#~ msgstr "Izuzmi" -#: includes/admin/media.php:330 -msgid "Prevents embedding content from your site" -msgstr "Sprječava ugrađivanje sadržaja s vaše web-lokacije" +#~ msgid "Exclude image by name" +#~ msgstr "Izuzmi sliku po imenu slike" -#: includes/admin/media.php:336 -msgid "Image sizes" -msgstr "Veličine slika" +#~ msgid "Add Image" +#~ msgstr "Dodaj sliku" -#: includes/admin/media.php:343 includes/admin/media.php:354 -msgid "Name" -msgstr "Naziv" +#~ msgid "" +#~ "Exclude images located in specific html containers like sliders and " +#~ "galleries" +#~ msgstr "" +#~ "Izuzmite slike koje se nalaze u određenim html kontejnerima kao npr. " +#~ "galerije" -#: includes/admin/media.php:344 includes/admin/media.php:360 -msgid "Width" -msgstr "Širina" +#~ msgid "Enter container id or class name" +#~ msgstr "Unesite ID kontejnera ili naziv klase" -#: includes/admin/media.php:345 includes/admin/media.php:366 -msgid "Height" -msgstr "Visina" +#~ msgid "Example" +#~ msgstr "Primjer" -#: includes/admin/media.php:346 includes/admin/media.php:372 -msgid "Crop" -msgstr "Izreži" +#~ msgid "Add Container" +#~ msgstr "Dodaj kontejner" -#: includes/admin/media.php:347 -msgid "Actions" -msgstr "Akcije" +#~ msgid "Exclude URL(s) from image optimization" +#~ msgstr "Izuzmi URL iz CSS optimizacije" -#: includes/admin/media.php:374 includes/functions/miscellaneous.php:259 -msgid "Yes" -msgstr "Da" +#~ msgid "Lazy load videos" +#~ msgstr "Lazy load videa" -#: includes/admin/media.php:379 -#, php-format -msgid "Remove image size %s" -msgstr "Ukloni veličinu slike %s" +#~ msgid "Disable Emoji" +#~ msgstr "Onemogući Emoji" -#: includes/admin/media.php:381 -msgid "Remove size" -msgstr "Makni veličinu" +#~ msgid "" +#~ "Use default emoji of visitor's browser instead of loading emoji from " +#~ "WordPress.org" +#~ msgstr "" +#~ "Upotrijebite zadani emotikon preglednika posjetitelja umjesto učitavanja " +#~ "emotikona sa WordPress.org" -#: includes/admin/media.php:391 -msgid "Add size" -msgstr "Dodaj veličinu" +#~ msgid "Disable embeds" +#~ msgstr "Onemogući ugrađivanje (embeds)" -#: includes/admin/media.php:392 -msgid "Restore default image sizes" -msgstr "Vraćanje zadanih veličina slika" +#~ msgid "Prevents embedding content from your site" +#~ msgstr "Sprječava ugrađivanje sadržaja s vaše web-lokacije" -#: includes/admin/media.php:392 -msgid "Restore image sizes" -msgstr "Vratite zadane veličine slika" +#~ msgid "Width" +#~ msgstr "Širina" -#: includes/admin/media.php:398 -msgid "Regenerate thumbnails every time you make some changes to image sizes" -msgstr "" -"Regenerirajte umanjene slike svaki put kada napravite neke promjene u " -"veličini slika" +#~ msgid "Height" +#~ msgstr "Visina" -#: includes/admin/media.php:400 -msgid "Regenerate thumbnails" -msgstr "Regenerirajte umanjene slike" +#~ msgid "Actions" +#~ msgstr "Akcije" -#: includes/admin/metabox.php:13 includes/admin/metabox.php:80 -#: includes/admin/metabox.php:131 includes/admin/metabox.php:183 -#: includes/admin/metabox.php:234 -msgid "Page URL will be added to exclude list" -msgstr "URL stranice će biti dodan na listu izuzetih URL-ova" +#, php-format +#~ msgid "Remove image size %s" +#~ msgstr "Ukloni veličinu slike %s" -#: includes/admin/metabox.php:41 includes/admin/metabox.php:68 -msgid "Exclude from cache" -msgstr "Izuzmi stranicu iz predmemorije" +#~ msgid "Remove size" +#~ msgstr "Makni veličinu" -#: includes/admin/metabox.php:46 -msgid "" -"This page is your website home page and it is affected by Exclude URL(s) " -"from cache option. Usually a home page is not excluded from cache. Please " -"check your exclude settings." -msgstr "" -"Ova stranica je početna stranica vaše web stranice i na nju utječu URL-ovi " -"dodani kao opcije izuzimanja iz predmemorije na stranici Predmemorija. " -"Obično početna stranica nije isključena iz predmemorije. Provjerite postavke " -"izuzimanja." +#~ msgid "Restore default image sizes" +#~ msgstr "Vraćanje zadanih veličina slika" -#: includes/admin/metabox.php:49 -msgid "This page is affected by URL(s) exclude options on Cache page" -msgstr "" -"Na izuzimanje ove stranice utječu URL-ovi dodani na stranici Predmemorija" +#~ msgid "Restore image sizes" +#~ msgstr "Vratite zadane veličine slika" -#: includes/admin/metabox.php:63 -msgid "" -"This page is your website home page.
    Do you want to exclude home page " -"from cache?" -msgstr "" -"Ova stranica je početna stranica vaše web stranice.
    Da li želite " -"izuzeti početnu stranicu iz predmemorije?" +#~ msgid "" +#~ "Regenerate thumbnails every time you make some changes to image sizes" +#~ msgstr "" +#~ "Regenerirajte umanjene slike svaki put kada napravite neke promjene u " +#~ "veličini slika" -#: includes/admin/metabox.php:107 includes/admin/metabox.php:121 -#: includes/admin/metabox.php:158 -msgid "Exclude from CSS optimization" -msgstr "Izuzmi stranicu iz CSS optimizacije" +#~ msgid "Page URL will be added to exclude list" +#~ msgstr "URL stranice će biti dodan na listu izuzetih URL-ova" -#: includes/admin/metabox.php:111 -msgid "This page is affected by URL(s) exclude options on CSS page" -msgstr "Na izuzimanje ove stranice utječu URL-ovi dodani na stranici CSS" +#~ msgid "" +#~ "This page is your website home page and it is affected by Exclude URL(s) " +#~ "from cache option. Usually a home page is not excluded from cache. Please " +#~ "check your exclude settings." +#~ msgstr "" +#~ "Ova stranica je početna stranica vaše web stranice i na nju utječu URL-" +#~ "ovi dodani kao opcije izuzimanja iz predmemorije na stranici " +#~ "Predmemorija. Obično početna stranica nije isključena iz predmemorije. " +#~ "Provjerite postavke izuzimanja." -#: includes/admin/metabox.php:162 -msgid "This page is affected by URL(s) exclude options on JavaScript page" -msgstr "" -"Na izuzimanje ove stranice utječu URL-ovi dodani na stranici JavaScript" +#~ msgid "This page is affected by URL(s) exclude options on Cache page" +#~ msgstr "" +#~ "Na izuzimanje ove stranice utječu URL-ovi dodani na stranici Predmemorija" -#: includes/admin/metabox.php:172 -msgid "Exclude from JS optimization" -msgstr "Izuzmi stranicu iz JS optimizacije" +#~ msgid "" +#~ "This page is your website home page.
    Do you want to exclude home " +#~ "page from cache?" +#~ msgstr "" +#~ "Ova stranica je početna stranica vaše web stranice.
    Da li želite " +#~ "izuzeti početnu stranicu iz predmemorije?" -#: includes/admin/metabox.php:209 includes/admin/metabox.php:223 -msgid "Exclude from Image optimization" -msgstr "Izuzmi stranicu iz optimizacije slika" +#~ msgid "This page is affected by URL(s) exclude options on CSS page" +#~ msgstr "Na izuzimanje ove stranice utječu URL-ovi dodani na stranici CSS" -#: includes/admin/metabox.php:213 includes/admin/metabox.php:264 -msgid "This page is affected by URL(s) exclude options on Media page" -msgstr "Na izuzimanje ove stranice utječu URL-ovi dodani na stranici Media" +#~ msgid "This page is affected by URL(s) exclude options on JavaScript page" +#~ msgstr "" +#~ "Na izuzimanje ove stranice utječu URL-ovi dodani na stranici JavaScript" -#: includes/admin/metabox.php:260 includes/admin/metabox.php:274 -msgid "Exclude from Video lazyload" -msgstr "Onemogući lazy load na ovoj stranici" +#~ msgid "Exclude from JS optimization" +#~ msgstr "Izuzmi stranicu iz JS optimizacije" -#: includes/admin/settings.php:16 -msgid "Import settings" -msgstr "Uvezi postavke" +#~ msgid "Exclude from Image optimization" +#~ msgstr "Izuzmi stranicu iz optimizacije slika" -#: includes/admin/settings.php:22 -msgid "Export settings" -msgstr "Izvezi postavke" +#~ msgid "This page is affected by URL(s) exclude options on Media page" +#~ msgstr "Na izuzimanje ove stranice utječu URL-ovi dodani na stranici Media" -#: includes/admin/settings.php:25 -msgid "Export" -msgstr "Izvezi" +#~ msgid "Exclude from Video lazyload" +#~ msgstr "Onemogući lazy load na ovoj stranici" -#: includes/admin/settings.php:34 -msgid "Server" -msgstr "Poslužitelj" +#~ msgid "Export" +#~ msgstr "Izvezi" -#: includes/admin/settings.php:39 -msgid "Nginx configuration" -msgstr "Nginx postavke" +#~ msgid "Nginx configuration" +#~ msgstr "Nginx postavke" -#: includes/admin/settings.php:43 #, php-format -msgid "" -"%s will work out of the box on Nginx servers, this rewrite rules are not " -"required. However, to optimize your website even more, you should add this " -"rules to your Nginx configuration file." -msgstr "" -"%s će raditi bez dodatnih postavki na Nginx poslužiteljima, ove definicije " -"nisu neophodne. Međutim, da biste dodatno optimizirali vašu web stranicu, " -"dodajte ove definicije u Nginx konfiguracijsku datoteku." - -#: includes/admin/settings.php:45 -msgid "Select all" -msgstr "Odabrati sve" +#~ msgid "" +#~ "%s will work out of the box on Nginx servers, this rewrite rules are not " +#~ "required. However, to optimize your website even more, you should add " +#~ "this rules to your Nginx configuration file." +#~ msgstr "" +#~ "%s će raditi bez dodatnih postavki na Nginx poslužiteljima, ove " +#~ "definicije nisu neophodne. Međutim, da biste dodatno optimizirali vašu " +#~ "web stranicu, dodajte ove definicije u Nginx konfiguracijsku datoteku." -#: includes/admin/settings.php:52 -msgid "Logs" -msgstr "Zapisi" +#~ msgid "Select all" +#~ msgstr "Odabrati sve" -#: includes/admin/settings.php:56 -msgid "Troubleshooting logging" -msgstr "Dnevnik" +#~ msgid "Logs" +#~ msgstr "Zapisi" -#: includes/admin/settings.php:60 -msgid "Enable troubleshooting logging" -msgstr "Omogući dnevnik" +#~ msgid "Troubleshooting logging" +#~ msgstr "Dnevnik" -#: includes/admin/settings.php:63 -msgid "These logs can be helpful for troubleshooting problems" -msgstr "Ovi zapisi mogu biti korisni za rješavanje problema" +#~ msgid "Enable troubleshooting logging" +#~ msgstr "Omogući dnevnik" -#: includes/admin/settings.php:69 -msgid "Log file content" -msgstr "Sadržaj datoteke dnevnika" +#~ msgid "These logs can be helpful for troubleshooting problems" +#~ msgstr "Ovi zapisi mogu biti korisni za rješavanje problema" -#: includes/admin/settings.php:72 -msgid "Content is auto refreshed every 10 seconds" -msgstr "Sadržaj se automatski osvježava svakih 10 sekundi" +#~ msgid "Log file content" +#~ msgstr "Sadržaj datoteke dnevnika" -#: includes/admin/settings.php:84 -msgid "Clear log file" -msgstr "Očisti datoteku dnevnika" +#~ msgid "Content is auto refreshed every 10 seconds" +#~ msgstr "Sadržaj se automatski osvježava svakih 10 sekundi" -#: includes/admin/settings.php:93 -msgid "Previous configuration settings" -msgstr "Prethodne postavke konfiguracije" +#~ msgid "Clear log file" +#~ msgstr "Očisti datoteku dnevnika" -#: includes/admin/settings.php:114 -msgid "Saved" -msgstr "Spremljeno" +#~ msgid "Previous configuration settings" +#~ msgstr "Prethodne postavke konfiguracije" -#: includes/admin/settings.php:117 -msgid "Load configuration settings saved on " -msgstr "Učitajte postavke konfiguracije spremljene u " +#~ msgid "Saved" +#~ msgstr "Spremljeno" -#: includes/admin/settings.php:120 -msgid "Load" -msgstr "Učitaj" +#~ msgid "Load configuration settings saved on " +#~ msgstr "Učitajte postavke konfiguracije spremljene u " -#: includes/classes/api.php:130 -#, php-format -msgid "Call to undefined method %s" -msgstr "" +#~ msgid "Load" +#~ msgstr "Učitaj" -#: includes/classes/cli.php:23 -msgid "Flushing the cache..." -msgstr "Čišćenje predmemorije..." +#~ msgid "Flushing the cache..." +#~ msgstr "Čišćenje predmemorije..." -#: includes/classes/cli.php:25 -msgid "Cache flushed." -msgstr "Predmemorija očišćena." +#~ msgid "Cache flushed." +#~ msgstr "Predmemorija očišćena." -#: includes/classes/cli.php:73 -msgid "Running tranisent cleanup" -msgstr "Pokrenuto čišćenje privremenih postavki" +#~ msgid "Running tranisent cleanup" +#~ msgstr "Pokrenuto čišćenje privremenih postavki" -#: includes/classes/cli.php:75 -msgid "Transient cleanup complete" -msgstr "Završeno čišćenje privremenih postavki" +#~ msgid "Transient cleanup complete" +#~ msgstr "Završeno čišćenje privremenih postavki" -#: includes/classes/cli.php:81 -msgid "Running revisions cleanup" -msgstr "Pokrenuto čišćenje revizija" +#~ msgid "Running revisions cleanup" +#~ msgstr "Pokrenuto čišćenje revizija" -#: includes/classes/cli.php:83 -msgid "Revisions cleanup complete" -msgstr "Završeno čišćenje revizija" +#~ msgid "Revisions cleanup complete" +#~ msgstr "Završeno čišćenje revizija" -#: includes/classes/cli.php:89 -msgid "Running drafts cleanup" -msgstr "Pokrenuto čišćenje skica" +#~ msgid "Running drafts cleanup" +#~ msgstr "Pokrenuto čišćenje skica" -#: includes/classes/cli.php:91 -msgid "Drafts cleanup complete" -msgstr "Pokrenuto čišćenje skica" +#~ msgid "Drafts cleanup complete" +#~ msgstr "Pokrenuto čišćenje skica" -#: includes/classes/cli.php:97 -msgid "Running trash cleanup" -msgstr "Pokrenuto čišćenje smeća" +#~ msgid "Running trash cleanup" +#~ msgstr "Pokrenuto čišćenje smeća" -#: includes/classes/cli.php:99 -msgid "Trash cleanup complete" -msgstr "Završeno čišćenje smeća" +#~ msgid "Trash cleanup complete" +#~ msgstr "Završeno čišćenje smeća" -#: includes/classes/cli.php:105 -msgid "Running spam cleanup" -msgstr "Pokrenuto čišćenje spam-a" +#~ msgid "Running spam cleanup" +#~ msgstr "Pokrenuto čišćenje spam-a" -#: includes/classes/cli.php:107 -msgid "Spam cleanup complete" -msgstr "Završeno čišćenje spam-a" +#~ msgid "Spam cleanup complete" +#~ msgstr "Završeno čišćenje spam-a" -#: includes/classes/cli.php:113 -msgid "Running cron tasks cleanup" -msgstr "Pokrenuto čišćenje zakazanih zadataka" +#~ msgid "Running cron tasks cleanup" +#~ msgstr "Pokrenuto čišćenje zakazanih zadataka" -#: includes/classes/cli.php:115 -msgid "Cron tasks cleanup complete" -msgstr "Završeno čišćenje zakazanih zadataka" +#~ msgid "Cron tasks cleanup complete" +#~ msgstr "Završeno čišćenje zakazanih zadataka" -#: includes/classes/cli.php:126 -msgid "Running database cleanup" -msgstr "Pokrenuto čišćenje baze" +#~ msgid "Running database cleanup" +#~ msgstr "Pokrenuto čišćenje baze" -#: includes/classes/cli.php:128 -msgid "Database cleanup complete" -msgstr "Završeno čišćenje baze" +#~ msgid "Database cleanup complete" +#~ msgstr "Završeno čišćenje baze" -#: includes/classes/parser.php:94 -msgid "error" -msgstr "greška" +#~ msgid "error" +#~ msgstr "greška" -#: includes/classes/parser.php:95 includes/classes/parser.php:98 -msgid "both head and body tag should be present in template file" -msgstr "oznaka head i body bi trebale biti prisutne u datoteci predloška" +#~ msgid "both head and body tag should be present in template file" +#~ msgstr "oznaka head i body bi trebale biti prisutne u datoteci predloška" -#: includes/classes/parser.php:932 -msgid "Optimized by" -msgstr "Optimizirano sa" +#~ msgid "Optimized by" +#~ msgstr "Optimizirano sa" -#: includes/classes/parser.php:956 #, php-format -msgid "Cache file was created in %s seconds on %s at %s" -msgstr "Datoteka predmemorije stvorena je za %s sekundi na dan %s u %s" +#~ msgid "Cache file was created in %s seconds on %s at %s" +#~ msgstr "Datoteka predmemorije stvorena je za %s sekundi na dan %s u %s" -#: includes/functions/admin.php:270 -msgid "Temporarily disable" -msgstr "Privremeno onemogući" - -#: includes/functions/backend.php:52 -#, php-format -msgid "" -"File advanced-cache.php is missing. If you updated your " -"installation of %s recently, try to deactivate and then activate the plugin " -"again." -msgstr "" +#~ msgid "Temporarily disable" +#~ msgstr "Privremeno onemogući" -#: includes/functions/backend.php:237 -msgid "is temporarily disabled" -msgstr "je privremeno onemogućen" +#~ msgid "is temporarily disabled" +#~ msgstr "je privremeno onemogućen" -#: includes/functions/backend.php:250 #, php-format -msgid "" -"%s: Log file is getting large, either clear the log or disable " -"troubleshooting logging" -msgstr "" -"%s: Datoteka dnevnika postaje sve veća, očistite zapise dnevnika ili " -"onemogućite zapisivanje u dnevnik" +#~ msgid "" +#~ "%s: Log file is getting large, either clear the log or disable " +#~ "troubleshooting logging" +#~ msgstr "" +#~ "%s: Datoteka dnevnika postaje sve veća, očistite zapise dnevnika ili " +#~ "onemogućite zapisivanje u dnevnik" -#: includes/functions/backend.php:262 #, php-format -msgid "%s: missing writing permissions for file .htaccess" -msgstr "%s: nedostaju dozvole za pisanje u datoteku .htaccess " +#~ msgid "%s: missing writing permissions for file .htaccess" +#~ msgstr "" +#~ "%s: nedostaju dozvole za pisanje u datoteku .htaccess " -#: includes/functions/backend.php:275 #, php-format -msgid "%s: enter Cloudflare credentials" -msgstr "%s: unesite Cloudflare podatke računa" +#~ msgid "%s: enter Cloudflare credentials" +#~ msgstr "%s: unesite Cloudflare podatke računa" -#: includes/functions/cron.php:41 -msgid "Every minute" -msgstr "Svake minute" +#~ msgid "Every minute" +#~ msgstr "Svake minute" -#: includes/functions/cron.php:46 -msgid "Every 5 minutes" -msgstr "Svakih 5 minuta" +#~ msgid "Every 5 minutes" +#~ msgstr "Svakih 5 minuta" -#: includes/functions/db.php:85 -msgid "You are doing it wrong" -msgstr "Vi to radite krivo" +#~ msgid "You are doing it wrong" +#~ msgstr "Vi to radite krivo" -#: includes/functions/files.php:350 -msgid "Log file cleared" -msgstr "Dnevnik je izbrisan" +#~ msgid "Log file cleared" +#~ msgstr "Dnevnik je izbrisan" -#: includes/functions/image.php:68 -msgid "Size name already in use" -msgstr "Naziv veličine već se koristi" +#~ msgid "Size name already in use" +#~ msgstr "Naziv veličine već se koristi" -#: includes/functions/image.php:190 #, php-format -msgid "%s image left" -msgid_plural "%s images left" -msgstr[0] "Ostala je %s slika" -msgstr[1] "Ostale su %s slike" -msgstr[2] "Ostalo je %s slika" - -#: includes/functions/image.php:202 -msgid "Done" -msgstr "Gotovo" - -#: includes/functions/miscellaneous.php:257 -msgid "Are you sure?" -msgstr "Da li ste sigurni?" +#~ msgid "%s image left" +#~ msgid_plural "%s images left" +#~ msgstr[0] "Ostala je %s slika" +#~ msgstr[1] "Ostale su %s slike" +#~ msgstr[2] "Ostalo je %s slika" -#: includes/functions/miscellaneous.php:264 -msgid "Something went wrong" -msgstr "Nešto je pošlo krivo" +#~ msgid "Done" +#~ msgstr "Gotovo" -#: includes/functions/miscellaneous.php:265 -msgid "Regenerating thumbs" -msgstr "Regeneriranje umanjenih slika" +#~ msgid "Are you sure?" +#~ msgstr "Da li ste sigurni?" -#: includes/functions/miscellaneous.php:266 -msgid "Regenerate thumbnails may take a long time. Do not close your browser." -msgstr "" -"Regeneriranje umanjenih slika može potrajati dugo. Ne zatvarajte preglednik." - -#: includes/functions/plugin.php:220 -msgid "The following plugins are not compatible with" -msgstr "Slijedeći dodaci nisu kompatibilni sa" +#~ msgid "Something went wrong" +#~ msgstr "Nešto je pošlo krivo" -#: includes/functions/plugin.php:227 -msgid "Deactivate" -msgstr "Deaktiviraj" +#~ msgid "Regenerating thumbs" +#~ msgstr "Regeneriranje umanjenih slika" -#: includes/functions/settings.php:57 -msgid "Invalid settings file" -msgstr "Nevažeća datoteka postavki" - -#: includes/functions/settings.php:269 -msgid "Settings saved" -msgstr "Postavke spremljene" +#~ msgid "" +#~ "Regenerate thumbnails may take a long time. Do not close your browser." +#~ msgstr "" +#~ "Regeneriranje umanjenih slika može potrajati dugo. Ne zatvarajte " +#~ "preglednik." -#: includes/functions/settings.php:330 -msgid "Settings file loaded" -msgstr "Datoteka postavki je učitana" +#~ msgid "The following plugins are not compatible with" +#~ msgstr "Slijedeći dodaci nisu kompatibilni sa" -#: includes/functions/settings.php:520 -msgid "Files list cleared" -msgstr "Lista izbrisana" +#~ msgid "Deactivate" +#~ msgstr "Deaktiviraj" -#. Plugin Name of the plugin/theme -msgid "WP Performance" -msgstr "WP Performance" +#~ msgid "Invalid settings file" +#~ msgstr "Nevažeća datoteka postavki" -#. Plugin URI of the plugin/theme -msgid "https://www.wp-performance.com" -msgstr "" +#~ msgid "Settings saved" +#~ msgstr "Postavke spremljene" -#. Description of the plugin/theme -msgid "WP Performance Optimizer" -msgstr "WP Performance Optimizer" +#~ msgid "Settings file loaded" +#~ msgstr "Datoteka postavki je učitana" -#. Author of the plugin/theme -msgid "Ante Laca" -msgstr "" +#~ msgid "Files list cleared" +#~ msgstr "Lista izbrisana" -#. Author URI of the plugin/theme -msgid "https://www.antelaca.xyz" -msgstr "" +#~ msgid "WP Performance Optimizer" +#~ msgstr "WP Performance Optimizer" #~ msgid "Cloudflare cache" #~ msgstr "Cloudflare predmemeorija" -#~ msgid "Varnish" -#~ msgstr "Varnish" - #~ msgid "If Varnish runs on your server, you need to activate this option." #~ msgstr "" #~ "Ako je Varnish instaliran na vašem poslužitelju, morate aktivirati ovu " @@ -1403,9 +2232,6 @@ msgstr "" #~ msgid "settings" #~ msgstr "settings" -#~ msgid "Cloudflare" -#~ msgstr "Cloudflare" - #~ msgid "Error" #~ msgstr "Greška" diff --git a/languages/wpp-zh_CN.mo b/languages/wpp-zh_CN.mo deleted file mode 100644 index d14bd84..0000000 Binary files a/languages/wpp-zh_CN.mo and /dev/null differ diff --git a/languages/wpp-zh_CN.po b/languages/wpp-zh_CN.po deleted file mode 100644 index dae0b49..0000000 --- a/languages/wpp-zh_CN.po +++ /dev/null @@ -1,1361 +0,0 @@ -msgid "" -msgstr "" -"Project-Id-Version: WP Performance\n" -"POT-Creation-Date: 2019-08-30 15:10+0200\n" -"PO-Revision-Date: 2019-08-30 15:11+0200\n" -"Last-Translator: WordPress大学 \n" -"Language-Team: WordPress淘宝网 \n" -"Language: zh_CN\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"X-Generator: Poedit 2.0.3\n" -"X-Poedit-Basepath: ..\n" -"Plural-Forms: nplurals=2; plural=(n > 1);\n" -"X-Poedit-Flags-xgettext: --add-comments=translators:\n" -"X-Poedit-WPHeader: wp-performance.php\n" -"X-Poedit-SourceCharset: UTF-8\n" -"X-Poedit-KeywordsList: __;_e;_n:1,2;_x:1,2c;_ex:1,2c;_nx:4c,1,2;esc_attr__;" -"esc_attr_e;esc_attr_x:1,2c;esc_html__;esc_html_e;esc_html_x:1,2c;_n_noop:1,2;" -"_nx_noop:3c,1,2;__ngettext_noop:1,2\n" -"X-Poedit-SearchPath-0: .\n" -"X-Poedit-SearchPathExcluded-0: *.js\n" - -#: includes/addons/cloudflare/cloudflare.php:55 -#, fuzzy -#| msgid "Cloudflare credentials" -msgid "Cloudflare - purge everything" -msgstr "Cloudflare凭据" - -#: includes/addons/cloudflare/cloudflare.php:56 -msgid "Cloudflare - purge custom URL(s)" -msgstr "" - -#: includes/addons/cloudflare/cloudflare.php:97 -msgid "Cloudflare API credentials not set" -msgstr "未设置Cloudflare API凭据" - -#: includes/addons/cloudflare/cloudflare.php:116 -msgid " Cloudflare cannot get zone details. Check your Cloudflare credentials" -msgstr " Cloudflare无法获取区域详细信息。检查您的Cloudflare凭据" - -#: includes/addons/cloudflare/cloudflare.php:123 -#, php-format -msgid "" -" Cloudflare zone %s is not activated. Please go to your Cloudflare dashboard " -"and activate it." -msgstr " Cloudflare区域%s未激活。请转到Cloudflare仪表板并激活它。" - -#: includes/addons/cloudflare/cloudflare.php:127 -#, php-format -msgid "" -" Cloudflare zone %s status is pending and these settings won't have any " -"effect on your website." -msgstr " Cloudflare 区域%s状态为待审,这些设置对您的网站没有任何影响。" - -#: includes/addons/cloudflare/cloudflare.php:142 -msgid " Cloudflare development mode not set" -msgstr " 未设置Cloudflare开发模式" - -#: includes/addons/cloudflare/cloudflare.php:151 -msgid " Cloudflare cache level not set" -msgstr " 未设置Cloudflare缓存级别" - -#: includes/addons/cloudflare/cloudflare.php:161 -msgid " Cloudflare browser cache expiration not set" -msgstr " 未设置Cloudflare浏览器缓存过期" - -#: includes/addons/cloudflare/cloudflare.php:175 -msgid " Cloudflare minify not set" -msgstr " 未设置Cloudflare压缩" - -#: includes/addons/cloudflare/cloudflare.php:187 -msgid " Cloudflare Rocket loader mode not set" -msgstr " 未设置Cloudflare Rocket加载器模式" - -#: includes/addons/cloudflare/cloudflare.php:197 -msgid " Cloudflare Brotli mode not set" -msgstr " 未设置Cloudflare Brotli模式" - -#: includes/addons/cloudflare/cloudflare.php:209 -msgid "Cloudflare settings saved" -msgstr "Cloudflare设置已保存" - -#: includes/addons/cloudflare/cloudflare.php:231 -msgid "Something went wrong. Cannot purge Cloudflare cache" -msgstr "有些不对劲。无法清除Cloudflare缓存" - -#: includes/addons/cloudflare/cloudflare.php:261 -msgid "Something went wrong. Cannot purge Cloudflare custom URL(s) cache" -msgstr "" - -#: includes/addons/cloudflare/views/addon.php:20 -msgid "Integrate your Cloudflare account with this add-on." -msgstr "使用此扩展程序将Cloudflare账户集成。" - -#: includes/addons/cloudflare/views/addon.php:27 -#: includes/addons/cloudflare/views/admin.php:82 -#: includes/addons/cloudflare/views/admin.php:175 -#: includes/addons/cloudflare/views/admin.php:187 -#: includes/addons/prefetch/views/addon.php:18 -#: includes/addons/varnish/views/addon.php:49 includes/functions/admin.php:267 -#: includes/functions/backend.php:238 -msgid "Enable" -msgstr "启用" - -#: includes/addons/cloudflare/views/admin.php:15 -msgid "Caching" -msgstr "缓存" - -#: includes/addons/cloudflare/views/admin.php:21 -msgid "Purge Cache" -msgstr "" - -#: includes/addons/cloudflare/views/admin.php:23 -msgid "Clear all Cloudflare cache" -msgstr "清除所有Cloudflare缓存" - -#: includes/addons/cloudflare/views/admin.php:23 -msgid "Purge everything" -msgstr "" - -#: includes/addons/cloudflare/views/admin.php:24 -msgid "Clear custom URL(s) from Cloudflare cache" -msgstr "" - -#: includes/addons/cloudflare/views/admin.php:24 -#: includes/addons/cloudflare/views/admin.php:29 -msgid "Purge custom URL(s)" -msgstr "" - -#: includes/addons/cloudflare/views/admin.php:49 includes/admin/cache.php:116 -#: includes/admin/cache.php:335 includes/admin/cache.php:355 -#: includes/admin/cache.php:414 includes/admin/cdn.php:66 -#: includes/admin/css.php:317 includes/admin/css.php:327 -#: includes/admin/includes/external_files.php:66 -#: includes/admin/includes/external_files.php:94 -#: includes/admin/includes/local_files.php:65 -#: includes/admin/includes/local_files.php:92 includes/admin/javascript.php:243 -#: includes/admin/javascript.php:253 includes/admin/media.php:66 -#: includes/admin/media.php:92 includes/admin/media.php:136 -#: includes/admin/media.php:156 includes/admin/media.php:238 -#: includes/admin/media.php:258 includes/functions/miscellaneous.php:258 -msgid "Remove" -msgstr "删除" - -#: includes/addons/cloudflare/views/admin.php:58 -#: includes/addons/cloudflare/views/admin.php:67 -msgid "" -"Any assets in the Cloudflare cache that match the URL(s) exactly will be " -"purged from the cache." -msgstr "" - -#: includes/addons/cloudflare/views/admin.php:70 includes/admin/cache.php:380 -#: includes/admin/css.php:351 includes/admin/includes/external_files.php:113 -#: includes/admin/includes/external_files.php:124 -#: includes/admin/includes/local_files.php:109 -#: includes/admin/includes/local_files.php:120 -#: includes/admin/javascript.php:277 includes/admin/media.php:180 -#: includes/admin/media.php:282 includes/functions/miscellaneous.php:260 -msgid "Add URL" -msgstr "添加网址" - -#: includes/addons/cloudflare/views/admin.php:78 -msgid "Development mode" -msgstr "开发模式" - -#: includes/addons/cloudflare/views/admin.php:85 -msgid "Temporarily activate development mode on your website." -msgstr "暂时激活您网站上的开发模式。" - -#: includes/addons/cloudflare/views/admin.php:86 -msgid "This setting will automatically turn off after 3 hours." -msgstr "此设置将在3小时后自动关闭。" - -#: includes/addons/cloudflare/views/admin.php:91 -msgid "Cache level" -msgstr "缓存级别" - -#: includes/addons/cloudflare/views/admin.php:94 -msgid "Aggressive - Standard" -msgstr "积极 - 标准" - -#: includes/addons/cloudflare/views/admin.php:95 -msgid "Simplified - Ignore query string" -msgstr "简化 - 忽略查询字符串" - -#: includes/addons/cloudflare/views/admin.php:96 -msgid "Basic - No query string" -msgstr "基本 - 没有查询字符串" - -#: includes/addons/cloudflare/views/admin.php:101 -msgid "" -"Aggressive: Delivers a different resource each time the query string changes." -msgstr "积极:每次查询字符串更改时提供不同的资源。" - -#: includes/addons/cloudflare/views/admin.php:102 -msgid "" -"Simplified: Delivers the same resource to everyone independent of the query " -"string." -msgstr "简化:向所有人提供与查询字符串无关的相同资源。" - -#: includes/addons/cloudflare/views/admin.php:103 -msgid "" -"Basic: Only delivers resources from cache when there is no query string." -msgstr "基本:只有在没有查询字符串时才从缓存中提供资源。" - -#: includes/addons/cloudflare/views/admin.php:118 -msgid "Browser Cache Expiration" -msgstr "浏览器缓存过期" - -#: includes/addons/cloudflare/views/admin.php:121 -msgid "Respect Existing Headers" -msgstr "尊重现有标题" - -#: includes/addons/cloudflare/views/admin.php:131 -msgid "" -"Browser cache TTL (in seconds) specifies how long CloudFlare-cached " -"resources will remain on your visitors computers." -msgstr "" -"浏览器缓存TTL(以秒为单位)指定CloudFlare缓存资源在访问者计算机上保留的时间。" - -#: includes/addons/cloudflare/views/admin.php:132 -msgid "The minimum TTL available depends on the plan level of the zone." -msgstr "可用的最小TTL取决于区域的计划级别。" - -#: includes/addons/cloudflare/views/admin.php:140 -msgid "Content" -msgstr "内容" - -#: includes/addons/cloudflare/views/admin.php:146 includes/admin/css.php:27 -#: includes/admin/includes/local_files.php:153 includes/admin/javascript.php:27 -msgid "Minify" -msgstr "压缩" - -#: includes/addons/cloudflare/views/admin.php:171 -msgid "Rocket Loader" -msgstr "Rocket 加载器" - -#: includes/addons/cloudflare/views/admin.php:178 -msgid "Rocket Loader is a asynchronous JavaScript loader." -msgstr "Rocket 加载器是一个异步JavaScript加载器。" - -#: includes/addons/cloudflare/views/admin.php:183 -msgid "Brotli" -msgstr "Brotli" - -#: includes/addons/cloudflare/views/admin.php:190 -msgid "" -"Speed up page load times for your visitor’s HTTPS traffic by applying Brotli " -"compression." -msgstr "通过应用Brotli压缩,加快访问者HTTPS流量的页面加载时间。" - -#: includes/addons/cloudflare/views/admin.php:198 includes/admin/addons.php:17 -#: includes/admin/cache.php:259 includes/admin/cdn.php:33 -#: includes/admin/css.php:119 includes/admin/database.php:183 -#: includes/admin/javascript.php:118 includes/admin/media.php:292 -#: includes/admin/settings.php:81 -msgid "Save changes" -msgstr "保存更改" - -#: includes/addons/cloudflare/views/admin.php:207 -msgid "Cloudflare credentials" -msgstr "Cloudflare凭据" - -#: includes/addons/cloudflare/views/admin.php:211 -msgid "API key" -msgstr "API密钥" - -#: includes/addons/cloudflare/views/admin.php:218 -msgid "Account email" -msgstr "账户邮箱" - -#: includes/addons/cloudflare/views/admin.php:223 -msgid "Zone ID" -msgstr "区域ID" - -#: includes/addons/prefetch/views/addon.php:9 -#: includes/addons/prefetch/views/addon.php:18 -msgid "Dynamic page preload" -msgstr "动态页面预加载" - -#: includes/addons/prefetch/views/addon.php:12 -msgid "Preloads a page right before a user clicks on link" -msgstr "在用户点击链接之前预加载页面" - -#: includes/addons/varnish/views/addon.php:20 -msgid "If Varnish runs on your server, you must activate this add-on." -msgstr "如果Varnish在您的服务器上运行,则必须激活此加载项。" - -#: includes/addons/varnish/views/addon.php:28 -msgid "Custom host" -msgstr "自定义主机" - -#: includes/addons/varnish/views/addon.php:41 -msgid "If you are using proxy, you may need this option" -msgstr "如果您使用的是代理主机,则可能需要此选项" - -#: includes/admin/addons.php:27 includes/admin/admin.php:30 -#: includes/admin/admin.php:45 includes/functions/admin.php:236 -#: includes/functions/admin.php:240 -msgid "Add-ons" -msgstr "扩展" - -#: includes/admin/addons.php:31 -#, php-format -msgid "Add more features to %s with add-ons." -msgstr "使用扩展程序向%s添加更多功能。" - -#: includes/admin/admin.php:23 includes/admin/admin.php:38 -#: includes/functions/admin.php:166 -msgid "Cache" -msgstr "缓存" - -#: includes/admin/admin.php:26 includes/admin/admin.php:41 -#: includes/functions/admin.php:196 includes/functions/admin.php:200 -msgid "Media" -msgstr "" - -#: includes/admin/admin.php:27 includes/admin/admin.php:42 -#: includes/functions/admin.php:206 includes/functions/admin.php:210 -msgid "Database" -msgstr "数据库" - -#: includes/admin/admin.php:29 includes/admin/admin.php:44 -#: includes/admin/settings.php:12 includes/functions/admin.php:170 -#: includes/functions/admin.php:226 includes/functions/admin.php:230 -#: includes/functions/admin.php:290 -msgid "Settings" -msgstr "设置" - -#: includes/admin/cache.php:11 -msgid "Enable cache" -msgstr "启用缓存" - -#: includes/admin/cache.php:15 -msgid "Reduces your server response time by serving static files to users" -msgstr "通过向用户提供静态文件,缩短服务器响应时间" - -#: includes/admin/cache.php:30 includes/admin/cache.php:194 -#: includes/admin/cache.php:246 -msgid "" -"Your web site is running on a Nginx server and some additional steps may be " -"required in order to use this option." -msgstr "您的网站在 Nginx 服务器上运行,可能需要一些其他步骤才能使用此选项。" - -#: includes/admin/cache.php:39 -msgid "Separate cache for mobile devices" -msgstr "移动设备独立缓存" - -#: includes/admin/cache.php:42 -msgid "Create a dedicated cache file for mobile devices" -msgstr "为移动设备创建专用缓存文件" - -#: includes/admin/cache.php:48 -msgid "Clear cache after" -msgstr "多久后清空缓存" - -#: includes/admin/cache.php:53 -msgid "minutes" -msgstr "分" - -#: includes/admin/cache.php:56 -msgid "hours" -msgstr "时" - -#: includes/admin/cache.php:59 -msgid "days" -msgstr "天" - -#: includes/admin/cache.php:66 -msgid "Clear cache when" -msgstr "什么时候清空缓存" - -#: includes/admin/cache.php:70 -msgid "A new post or page is published or updated" -msgstr "发布或更新文章、页面时" - -#: includes/admin/cache.php:75 -msgid "A post or page is deleted" -msgstr "文章或页面被删除时" - -#: includes/admin/cache.php:80 -msgid "settings are saved" -msgstr "设置保存时" - -#: includes/admin/cache.php:86 -msgid "Clear cache options" -msgstr "" - -#: includes/admin/cache.php:90 -msgid "Keep generated CSS/JS files" -msgstr "" - -#: includes/admin/cache.php:96 -msgid "Cache preloading" -msgstr "高速缓存预加载" - -#: includes/admin/cache.php:126 includes/admin/cache.php:136 -msgid "Enter path to XML sitemap which will be used for cache preloading" -msgstr "输入将用于缓存预加载的 xml 站点地图的路径" - -#: includes/admin/cache.php:139 -msgid "Add Sitemap" -msgstr "添加网站地图" - -#: includes/admin/cache.php:147 -msgid "Browser caching" -msgstr "浏览器缓存" - -#: includes/admin/cache.php:151 -msgid "Leverage browser caching" -msgstr "启用浏览器缓存" - -#: includes/admin/cache.php:176 -msgid "" -"Setting an expiry date in the HTTP headers for static resources instructs " -"the browser to load previously downloaded resources from local disk rather " -"than over the network" -msgstr "" -"在静态资源的 HTTP 标头中设置到期日期指示浏览器从本地磁盘而不是通过网络加载以" -"前下载的资源" - -#: includes/admin/cache.php:183 includes/admin/cache.php:235 -msgid "" -"This option is turned ON automatically for all sites in Wordpress multisite" -msgstr "" - -#: includes/admin/cache.php:204 -msgid "Enable gzip compression" -msgstr "启用 gzip 压缩" - -#: includes/admin/cache.php:228 -msgid "" -"Compressing resources with gzip reduce the number of bytes sent over the " -"network" -msgstr "使用 gzip 压缩资源可减少通过网络发送的字节数" - -#: includes/admin/cache.php:268 -msgid "Cache statistics" -msgstr "缓存统计信息" - -#: includes/admin/cache.php:269 includes/functions/admin.php:155 -#: includes/functions/admin.php:160 -msgid "Clear cache" -msgstr "清除缓存" - -#: includes/admin/cache.php:291 -msgid "HTML files" -msgstr "HTML文件" - -#: includes/admin/cache.php:294 -msgid "CSS files" -msgstr "CSS文件" - -#: includes/admin/cache.php:297 -msgid "JavaScript files" -msgstr "JavaScript文件" - -#: includes/admin/cache.php:302 -msgid "Total cache size" -msgstr "缓存总大小" - -#: includes/admin/cache.php:313 -msgid "Exclude URL(s) from cache" -msgstr "从缓存中排除网址" - -#: includes/admin/cache.php:334 includes/admin/css.php:316 -#: includes/admin/javascript.php:242 includes/admin/media.php:135 -#: includes/admin/media.php:237 -#, php-format -msgid "Remove %s from excluded URL(s)?" -msgstr "从已排除的网址中删除%s?" - -#: includes/admin/cache.php:365 includes/admin/cache.php:377 -#: includes/admin/cdn.php:75 includes/admin/cdn.php:86 -#: includes/admin/css.php:336 includes/admin/css.php:348 -#: includes/admin/javascript.php:262 includes/admin/javascript.php:274 -#: includes/admin/media.php:165 includes/admin/media.php:177 -#: includes/admin/media.php:267 includes/admin/media.php:279 -msgid "Use {numbers} to match only numbers" -msgstr "使用 {numbers} 来匹配数字" - -#: includes/admin/cache.php:366 includes/admin/cache.php:377 -#: includes/admin/cdn.php:76 includes/admin/cdn.php:86 -#: includes/admin/css.php:337 includes/admin/css.php:348 -#: includes/admin/javascript.php:263 includes/admin/javascript.php:274 -#: includes/admin/media.php:166 includes/admin/media.php:177 -#: includes/admin/media.php:268 includes/admin/media.php:279 -msgid "Use {letters} to match only letters" -msgstr "使用 {letters} 来匹配字母" - -#: includes/admin/cache.php:367 includes/admin/cache.php:377 -#: includes/admin/cdn.php:77 includes/admin/cdn.php:86 -#: includes/admin/css.php:338 includes/admin/css.php:348 -#: includes/admin/javascript.php:264 includes/admin/javascript.php:274 -#: includes/admin/media.php:167 includes/admin/media.php:177 -#: includes/admin/media.php:269 includes/admin/media.php:279 -msgid "Use {any} to match any string" -msgstr "使用 {any} 来匹配任何字符串" - -#: includes/admin/cache.php:368 includes/admin/cache.php:377 -#: includes/admin/css.php:339 includes/admin/css.php:348 -#: includes/admin/javascript.php:265 includes/admin/javascript.php:274 -#: includes/admin/media.php:168 includes/admin/media.php:177 -#: includes/admin/media.php:270 includes/admin/media.php:279 -msgid "Use {all} to match all" -msgstr "使用 {all} 来匹配任何字符串" - -#: includes/admin/cache.php:392 -msgid "Exclude User Agent(s) from cache" -msgstr "从缓存中排除用户代理" - -#: includes/admin/cache.php:427 -msgid "Add User Agent" -msgstr "添加用户代理" - -#: includes/admin/cache.php:437 -msgid "Exclude search engines" -msgstr "排除搜索引擎" - -#: includes/admin/cdn.php:12 -msgid "Enable CDN" -msgstr "启用CDN" - -#: includes/admin/cdn.php:16 -msgid "" -"All URL(s) of static files ( CSS, JavaScript and Images ) will be rewritten " -"to the CDN hostname you provide. " -msgstr "" -"所有静态文件 (CSS、JavaScript 和图片) 的网址都将被重写到您提供的 CDN 主机" -"名。 " - -#: includes/admin/cdn.php:23 -msgid "CDN hostname" -msgstr "CDN主机名" - -#: includes/admin/cdn.php:43 -msgid "Exclude file(s) from CDN" -msgstr "从CDN中排除文件" - -#: includes/admin/cdn.php:89 -msgid "Add file" -msgstr "添加文件" - -#: includes/admin/css.php:26 includes/admin/javascript.php:26 -msgid "File" -msgstr "文件" - -#: includes/admin/css.php:28 includes/admin/includes/local_files.php:171 -#: includes/admin/javascript.php:28 -msgid "Inline" -msgstr "内联" - -#: includes/admin/css.php:29 includes/admin/includes/local_files.php:189 -#: includes/admin/javascript.php:29 -msgid "Combine" -msgstr "合并" - -#: includes/admin/css.php:30 includes/admin/includes/external_files.php:152 -#: includes/admin/includes/local_files.php:213 includes/admin/javascript.php:30 -msgid "Disable" -msgstr "禁用" - -#: includes/admin/css.php:37 includes/admin/javascript.php:37 -msgid "Update all files in list below" -msgstr "更新下面列表中的所有文件" - -#: includes/admin/css.php:47 includes/admin/javascript.php:47 -msgid "Theme" -msgstr "主题" - -#: includes/admin/css.php:69 includes/admin/javascript.php:69 -msgid "Plugins" -msgstr "插件" - -#: includes/admin/css.php:92 includes/admin/javascript.php:92 -msgid "External resources" -msgstr "外部资源" - -#: includes/admin/css.php:115 includes/admin/javascript.php:114 -msgid "" -"If some of the files are missing from this list, enable Cache preloading " -"option." -msgstr "如果此列表中缺少某些文件,请启用缓存预加载选项。" - -#: includes/admin/css.php:122 includes/admin/javascript.php:121 -#, php-format -msgid "Clear collected %s files list.%s This option will also clear the cache." -msgstr "清除收集到的 %s 文件列表。%s 这个选项也将会清除缓存。" - -#: includes/admin/css.php:125 includes/admin/javascript.php:124 -msgid "Update files list" -msgstr "清除文件列表" - -#: includes/admin/css.php:130 -msgid "CSS files not found" -msgstr "找不到 CSS 文件" - -#: includes/admin/css.php:134 includes/admin/javascript.php:133 -msgid "Reload" -msgstr "刷新" - -#: includes/admin/css.php:142 -msgid "CSS settings" -msgstr "CSS 设置" - -#: includes/admin/css.php:158 -msgid "Minify inline CSS" -msgstr "压缩内联 CSS" - -#: includes/admin/css.php:166 -msgid "Asynchronously load CSS" -msgstr "异步加载 CSS" - -#: includes/admin/css.php:176 includes/admin/css.php:178 -msgid "Show critical CSS" -msgstr "显示关键CSS" - -#: includes/admin/css.php:177 includes/admin/css.php:178 -msgid "Hide critical CSS" -msgstr "隐藏关键CSS" - -#: includes/admin/css.php:188 -msgid "Eliminates render-blocking CSS" -msgstr "消除了渲染阻止CSS" - -#: includes/admin/css.php:194 -msgid "" -"Loading CSS asynchronously will produce FOUC effect (a Flash Of Unstyled " -"Content). In order to minimize the FOUC effect, use critical CSS path." -msgstr "" -"异步加载 CSS 将产生 FOUC 效果 (未设置样式内容的 flash)。为了最大限度地减少 " -"FOUC 效应,请使用关键 CSS 路径。" - -#: includes/admin/css.php:202 -msgid "Critical CSS path" -msgstr "关键 CSS 路径" - -#: includes/admin/css.php:207 -msgid "Enter critical CSS path definitions" -msgstr "输入关键 CSS 路径" - -#: includes/admin/css.php:212 -msgid "Generate critical CSS path" -msgstr "生成关键 CSS 路径" - -#: includes/admin/css.php:227 -msgid "Combine Google Fonts" -msgstr "合并谷歌字体" - -#: includes/admin/css.php:232 -msgid "Load all google fonts in one HTTP request" -msgstr "在一个 HTTP 请求中加载所有谷歌字体" - -#: includes/admin/css.php:241 -msgid "Disable CSS optimization for logged-in users" -msgstr "对已登录用户不启用CSS优化" - -#: includes/admin/css.php:252 includes/admin/javascript.php:178 -msgid "Resource Hints" -msgstr "资源提示" - -#: includes/admin/css.php:259 includes/admin/javascript.php:185 -msgid "Origins" -msgstr "来源" - -#: includes/admin/css.php:286 includes/admin/javascript.php:212 -msgid "DNS prefetching can make external resources load faster" -msgstr "DNS 预加载可以使外部资源加载速度更快" - -#: includes/admin/css.php:287 includes/admin/javascript.php:213 -msgid "Preconnect can remove additional roundtrips and reduce request latency" -msgstr "预连接可以删除其他往返并减少请求延迟" - -#: includes/admin/css.php:295 -msgid "Exclude URL(s) from CSS optimization" -msgstr "从 CSS 优化中排除网址" - -#: includes/admin/database.php:30 includes/admin/database.php:35 -msgid "Delete all pages, posts and comments from trash" -msgstr "从回收站中删除所有页面、文章和评论" - -#: includes/admin/database.php:31 includes/admin/database.php:55 -#: includes/admin/database.php:82 includes/admin/database.php:105 -#: includes/admin/database.php:132 includes/admin/database.php:157 -msgid "Delete" -msgstr "删除" - -#: includes/admin/database.php:34 -msgid "Trash" -msgstr "回收站" - -#: includes/admin/database.php:41 includes/admin/database.php:65 -#: includes/admin/database.php:92 includes/admin/database.php:115 -#: includes/admin/database.php:142 includes/admin/database.php:167 -msgid "Enable automatic cleanup" -msgstr "启用自动清理" - -#: includes/admin/database.php:54 includes/admin/database.php:59 -msgid "Delete all spam comments" -msgstr "删除所有垃圾评论" - -#: includes/admin/database.php:58 -msgid "Spam" -msgstr "垃圾评论" - -#: includes/admin/database.php:81 includes/admin/database.php:86 -msgid "Delete all revisions" -msgstr "删除所有修订版本" - -#: includes/admin/database.php:85 -msgid "Revisions" -msgstr "修订" - -#: includes/admin/database.php:104 includes/admin/database.php:109 -msgid "Delete all expired transients" -msgstr "删除所有过期的瞬态缓存" - -#: includes/admin/database.php:108 -msgid "Transients" -msgstr "瞬态缓存(Transients)" - -#: includes/admin/database.php:131 includes/admin/database.php:136 -msgid "Delete all auto drafts" -msgstr "删除所有自动草稿" - -#: includes/admin/database.php:135 -msgid "Auto Drafts" -msgstr "自动草稿" - -#: includes/admin/database.php:156 includes/admin/database.php:161 -msgid "Delete all unused scheduled tasks" -msgstr "删除所有未使用的计划任务" - -#: includes/admin/database.php:160 -msgid "Scheduled tasks" -msgstr "计划任务" - -#: includes/admin/database.php:179 -msgid "" -"Backup your database before running any of these cleanup actions. Once a " -"database cleanup has been performed, there is no way to undo it." -msgstr "" -"在运行任何这些清理操作之前备份你的数据库。一旦执行了数据库清理,就无法撤消" -"它。" - -#: includes/admin/database.php:185 includes/admin/database.php:186 -msgid "Delete all" -msgstr "全部删除" - -#: includes/admin/database.php:194 -msgid "Automatic database cleanup" -msgstr "自动清理数据库" - -#: includes/admin/database.php:200 -msgid "Schedule" -msgstr "计划" - -#: includes/admin/database.php:202 -msgid "Not scheduled" -msgstr "无计划任务" - -#: includes/admin/database.php:203 includes/functions/cron.php:26 -msgid "Daily" -msgstr "按天" - -#: includes/admin/database.php:204 includes/functions/cron.php:31 -msgid "Weekly" -msgstr "按周" - -#: includes/admin/database.php:205 includes/functions/cron.php:36 -msgid "Monthly" -msgstr "按月" - -#: includes/admin/database.php:208 -msgid "Next run" -msgstr "下一次运行" - -#: includes/admin/database.php:214 -msgid "Not set" -msgstr "没有设置" - -#: includes/admin/includes/external_files.php:31 -#: includes/admin/includes/local_files.php:31 -#: includes/functions/miscellaneous.php:261 -msgid "Disable everywhere" -msgstr "在所有地方禁用" - -#: includes/admin/includes/external_files.php:35 -#: includes/admin/includes/local_files.php:35 -#: includes/functions/miscellaneous.php:262 -msgid "Disable only on selected URL" -msgstr "仅在选定的网址上禁用" - -#: includes/admin/includes/external_files.php:39 -#: includes/admin/includes/local_files.php:39 -#: includes/functions/miscellaneous.php:263 -msgid "Disable everywhere except on selected URL" -msgstr "在所选网址以外的任何地方禁用" - -#: includes/admin/javascript.php:129 -msgid "JavaScript files not found" -msgstr "找不到 JavaScript 文件" - -#: includes/admin/javascript.php:142 -msgid "JavaScript settings" -msgstr "JavaScript 设置" - -#: includes/admin/javascript.php:150 -msgid "Minify inline JavaScript" -msgstr "压缩内联 JavaScript" - -#: includes/admin/javascript.php:157 -msgid "Asynchronously load JavaScript" -msgstr "异步加载 JavaScript" - -#: includes/admin/javascript.php:161 -msgid "Eliminates render-blocking JavaScript" -msgstr "消除了阻止渲染的 JavaScript" - -#: includes/admin/javascript.php:167 -msgid "Disable JavaScript optimization for logged-in users" -msgstr "对已登录的用户禁用 JavaScript 优化" - -#: includes/admin/javascript.php:221 -msgid "Exclude URL(s) from JavaScript optimization" -msgstr "从 JavaScript 优化中排除网址" - -#: includes/admin/media.php:12 -msgid "Images" -msgstr "图片" - -#: includes/admin/media.php:16 includes/admin/media.php:192 -msgid "Lazy load" -msgstr "延迟加载" - -#: includes/admin/media.php:20 -msgid "Lazy load images" -msgstr "延迟加载图片" - -#: includes/admin/media.php:24 includes/admin/media.php:209 -msgid "Reduces the number of HTTP requests and improves loading time" -msgstr "减少 HTTP 请求的数量并缩短加载时间" - -#: includes/admin/media.php:34 -msgid "Disable lazy load on mobile devices" -msgstr "在移动设备上禁用延迟加载" - -#: includes/admin/media.php:40 -msgid "Responsive images" -msgstr "响应式图片" - -#: includes/admin/media.php:44 -msgid "Force images to use srcset attribute" -msgstr "强制图片使用 srcset 属性" - -#: includes/admin/media.php:47 -msgid "" -"Loads the best optimized image depending on users screen size and image " -"sizes settings" -msgstr "根据用户屏幕大小和图片大小设置加载最佳优化的图片" - -#: includes/admin/media.php:52 -msgid "Exclude" -msgstr "排除" - -#: includes/admin/media.php:55 -msgid "Exclude image by name" -msgstr "按名称排除图片" - -#: includes/admin/media.php:72 -msgid "Add Image" -msgstr "添加图片" - -#: includes/admin/media.php:81 -msgid "" -"Exclude images located in specific html containers like sliders and galleries" -msgstr "排除位于特定 HTML 容器中的图片,如滑块和图库" - -#: includes/admin/media.php:99 includes/admin/media.php:108 -msgid "Enter container id or class name" -msgstr "输入容器 id 或类名" - -#: includes/admin/media.php:100 includes/admin/media.php:108 -msgid "Example" -msgstr "例子" - -#: includes/admin/media.php:108 -msgid "Add Container" -msgstr "添加容器" - -#: includes/admin/media.php:116 -msgid "Exclude URL(s) from image optimization" -msgstr "从图片优化中排除网址" - -#: includes/admin/media.php:188 -msgid "Videos" -msgstr "" - -#: includes/admin/media.php:204 -msgid "Lazy load videos" -msgstr "" - -#: includes/admin/media.php:218 -msgid "Exclude URL(s)" -msgstr "排除网址" - -#: includes/admin/media.php:303 -msgid "Emoji" -msgstr "" - -#: includes/admin/media.php:310 -msgid "Disable Emoji" -msgstr "" - -#: includes/admin/media.php:314 -msgid "" -"Use default emoji of visitor's browser instead of loading emoji from " -"WordPress.org" -msgstr "" - -#: includes/admin/media.php:319 -msgid "Embeds" -msgstr "" - -#: includes/admin/media.php:326 -msgid "Disable embeds" -msgstr "" - -#: includes/admin/media.php:330 -msgid "Prevents embedding content from your site" -msgstr "" - -#: includes/admin/media.php:336 -msgid "Image sizes" -msgstr "图片尺寸" - -#: includes/admin/media.php:343 includes/admin/media.php:354 -msgid "Name" -msgstr "名称" - -#: includes/admin/media.php:344 includes/admin/media.php:360 -msgid "Width" -msgstr "宽" - -#: includes/admin/media.php:345 includes/admin/media.php:366 -msgid "Height" -msgstr "高" - -#: includes/admin/media.php:346 includes/admin/media.php:372 -msgid "Crop" -msgstr "裁剪" - -#: includes/admin/media.php:347 -msgid "Actions" -msgstr "操作" - -#: includes/admin/media.php:374 includes/functions/miscellaneous.php:259 -msgid "Yes" -msgstr "是" - -#: includes/admin/media.php:379 -#, php-format -msgid "Remove image size %s" -msgstr "删除图片大小 %s" - -#: includes/admin/media.php:381 -msgid "Remove size" -msgstr "删除大小" - -#: includes/admin/media.php:391 -msgid "Add size" -msgstr "添加大小" - -#: includes/admin/media.php:392 -msgid "Restore default image sizes" -msgstr "恢复默认图片大小" - -#: includes/admin/media.php:392 -msgid "Restore image sizes" -msgstr "恢复图片大小" - -#: includes/admin/media.php:398 -msgid "Regenerate thumbnails every time you make some changes to image sizes" -msgstr "每次对图片大小进行某些更改时,都会重新生成缩略图" - -#: includes/admin/media.php:400 -msgid "Regenerate thumbnails" -msgstr "重新生成缩略图" - -#: includes/admin/metabox.php:13 includes/admin/metabox.php:80 -#: includes/admin/metabox.php:131 includes/admin/metabox.php:183 -#: includes/admin/metabox.php:234 -msgid "Page URL will be added to exclude list" -msgstr "页面网址将被添加排除列表" - -#: includes/admin/metabox.php:41 includes/admin/metabox.php:68 -msgid "Exclude from cache" -msgstr "从缓存中排除" - -#: includes/admin/metabox.php:46 -msgid "" -"This page is your website home page and it is affected by Exclude URL(s) " -"from cache option. Usually a home page is not excluded from cache. Please " -"check your exclude settings." -msgstr "" -"此页面是您的网站主页,它受缓存选项中的排除网址影响。通常,主页不会从缓存中排" -"除。请检查您的排除设置。" - -#: includes/admin/metabox.php:49 -msgid "This page is affected by URL(s) exclude options on Cache page" -msgstr "此页面受缓存页面上的网址排除选项的影响" - -#: includes/admin/metabox.php:63 -msgid "" -"This page is your website home page.
    Do you want to exclude home page " -"from cache?" -msgstr "此页面是您的网站主页。
    要从缓存中排除主页吗?" - -#: includes/admin/metabox.php:107 includes/admin/metabox.php:121 -#: includes/admin/metabox.php:158 -msgid "Exclude from CSS optimization" -msgstr "从CSS优化中排除" - -#: includes/admin/metabox.php:111 -msgid "This page is affected by URL(s) exclude options on CSS page" -msgstr "此页面受CSS页面上网址排除选项的影响" - -#: includes/admin/metabox.php:162 -msgid "This page is affected by URL(s) exclude options on JavaScript page" -msgstr "此页面受JavaScript页面上的网址排除选项的影响" - -#: includes/admin/metabox.php:172 -msgid "Exclude from JS optimization" -msgstr "从JS优化中排除" - -#: includes/admin/metabox.php:209 includes/admin/metabox.php:223 -msgid "Exclude from Image optimization" -msgstr "从图片优化中排除" - -#: includes/admin/metabox.php:213 includes/admin/metabox.php:264 -msgid "This page is affected by URL(s) exclude options on Media page" -msgstr "" - -#: includes/admin/metabox.php:260 includes/admin/metabox.php:274 -msgid "Exclude from Video lazyload" -msgstr "" - -#: includes/admin/settings.php:16 -msgid "Import settings" -msgstr "导入设置" - -#: includes/admin/settings.php:22 -msgid "Export settings" -msgstr "导出设置" - -#: includes/admin/settings.php:25 -msgid "Export" -msgstr "导出" - -#: includes/admin/settings.php:34 -msgid "Server" -msgstr "服务器" - -#: includes/admin/settings.php:39 -msgid "Nginx configuration" -msgstr "Nginx 配置" - -#: includes/admin/settings.php:43 -#, php-format -msgid "" -"%s will work out of the box on Nginx servers, this rewrite rules are not " -"required. However, to optimize your website even more, you should add this " -"rules to your Nginx configuration file." -msgstr "" -"%s 将在 Nginx 服务器上开箱即用,此重写规则不是必需的。但是,为了进一步优化您" -"的网站,您应该将此规则添加到您的 Nginx 配置文件。" - -#: includes/admin/settings.php:45 -msgid "Select all" -msgstr "全选" - -#: includes/admin/settings.php:52 -msgid "Logs" -msgstr "日志" - -#: includes/admin/settings.php:56 -msgid "Troubleshooting logging" -msgstr "故障排除日志" - -#: includes/admin/settings.php:60 -msgid "Enable troubleshooting logging" -msgstr "启用故障排除日志" - -#: includes/admin/settings.php:63 -msgid "These logs can be helpful for troubleshooting problems" -msgstr "这些日志可帮助解决问题" - -#: includes/admin/settings.php:69 -msgid "Log file content" -msgstr "记录文件内容" - -#: includes/admin/settings.php:72 -msgid "Content is auto refreshed every 10 seconds" -msgstr "内容每10秒自动刷新一次" - -#: includes/admin/settings.php:84 -msgid "Clear log file" -msgstr "清除日志文件" - -#: includes/admin/settings.php:93 -msgid "Previous configuration settings" -msgstr "以前的配置设置" - -#: includes/admin/settings.php:114 -msgid "Saved" -msgstr "保存于" - -#: includes/admin/settings.php:117 -msgid "Load configuration settings saved on " -msgstr "加载配置设置保存于 " - -#: includes/admin/settings.php:120 -msgid "Load" -msgstr "加载" - -#: includes/classes/api.php:130 -#, php-format -msgid "Call to undefined method %s" -msgstr "调用未定义的方法%s" - -#: includes/classes/cli.php:23 -msgid "Flushing the cache..." -msgstr "刷新缓存......" - -#: includes/classes/cli.php:25 -msgid "Cache flushed." -msgstr "缓存已刷新。" - -#: includes/classes/cli.php:73 -msgid "Running tranisent cleanup" -msgstr "运行tranisent清理" - -#: includes/classes/cli.php:75 -msgid "Transient cleanup complete" -msgstr "Transient清理完成" - -#: includes/classes/cli.php:81 -msgid "Running revisions cleanup" -msgstr "运行修订清理" - -#: includes/classes/cli.php:83 -msgid "Revisions cleanup complete" -msgstr "修订清理完成" - -#: includes/classes/cli.php:89 -msgid "Running drafts cleanup" -msgstr "运行草稿清理" - -#: includes/classes/cli.php:91 -msgid "Drafts cleanup complete" -msgstr "草稿清理完成" - -#: includes/classes/cli.php:97 -msgid "Running trash cleanup" -msgstr "运行垃圾清理" - -#: includes/classes/cli.php:99 -msgid "Trash cleanup complete" -msgstr "垃圾清理完成" - -#: includes/classes/cli.php:105 -msgid "Running spam cleanup" -msgstr "运行垃圾评论清理" - -#: includes/classes/cli.php:107 -msgid "Spam cleanup complete" -msgstr "垃圾评论清理完成" - -#: includes/classes/cli.php:113 -msgid "Running cron tasks cleanup" -msgstr "运行计划任务清理" - -#: includes/classes/cli.php:115 -msgid "Cron tasks cleanup complete" -msgstr "计划任务清理完成" - -#: includes/classes/cli.php:126 -msgid "Running database cleanup" -msgstr "运行数据库清理" - -#: includes/classes/cli.php:128 -msgid "Database cleanup complete" -msgstr "数据库清理完成" - -#: includes/classes/parser.php:94 -msgid "error" -msgstr "错误" - -#: includes/classes/parser.php:95 includes/classes/parser.php:98 -msgid "both head and body tag should be present in template file" -msgstr "head 和 body 标记都应存在模板文件中" - -#: includes/classes/parser.php:932 -msgid "Optimized by" -msgstr "已优化来自" - -#: includes/classes/parser.php:956 -#, php-format -msgid "Cache file was created in %s seconds on %s at %s" -msgstr "缓存文件创建于 %s 秒,%s 于 %s" - -#: includes/functions/admin.php:270 -msgid "Temporarily disable" -msgstr "暂时禁用" - -#: includes/functions/backend.php:52 -#, php-format -msgid "" -"File advanced-cache.php is missing. If you updated your " -"installation of %s recently, try to deactivate and then activate the plugin " -"again." -msgstr "" - -#: includes/functions/backend.php:237 -msgid "is temporarily disabled" -msgstr "暂时禁用" - -#: includes/functions/backend.php:250 -#, php-format -msgid "" -"%s: Log file is getting large, either clear the log or disable " -"troubleshooting logging" -msgstr "%s: 日志文件越来越大,可以清除日志,也可以禁用故障排除日志记录" - -#: includes/functions/backend.php:262 -#, php-format -msgid "%s: missing writing permissions for file .htaccess" -msgstr "%s: 缺少 . htaccess 文件的写入权限 " - -#: includes/functions/backend.php:275 -#, php-format -msgid "%s: enter Cloudflare credentials" -msgstr "%s:输入Cloudflare凭据" - -#: includes/functions/cron.php:41 -msgid "Every minute" -msgstr "每1分钟" - -#: includes/functions/cron.php:46 -msgid "Every 5 minutes" -msgstr "每5分钟" - -#: includes/functions/db.php:85 -msgid "You are doing it wrong" -msgstr "你做错了" - -#: includes/functions/image.php:68 -msgid "Size name already in use" -msgstr "已在使用的大小名称" - -#: includes/functions/image.php:190 -#, php-format -msgid "%s image left" -msgid_plural "%s images left" -msgstr[0] "剩余 %s 图片" -msgstr[1] "剩余 %s 图片" - -#: includes/functions/image.php:202 -msgid "Done" -msgstr "完成" - -#: includes/functions/miscellaneous.php:257 -msgid "Are you sure?" -msgstr "你确定?" - -#: includes/functions/miscellaneous.php:264 -msgid "Something went wrong" -msgstr "出了些问题" - -#: includes/functions/miscellaneous.php:265 -msgid "Regenerating thumbs" -msgstr "重新生成缩略图" - -#: includes/functions/miscellaneous.php:266 -msgid "Regenerate thumbnails may take a long time. Do not close your browser." -msgstr "重新生成缩略图可能需要很长时间。不要关闭浏览器。" - -#: includes/functions/plugin.php:220 -msgid "The following plugins are not compatible with" -msgstr "以下插件不兼容" - -#: includes/functions/plugin.php:227 -msgid "Deactivate" -msgstr "停用" - -#. Plugin Name of the plugin/theme -msgid "WP Performance" -msgstr "WP性能" - -#. Plugin URI of the plugin/theme -msgid "https://www.wp-performance.com" -msgstr "https://www.wp-performance.com" - -#. Description of the plugin/theme -msgid "WP Performance Optimizer" -msgstr "" -"WP性能优化插件,由 WordPress大学 https://www.wpdaxue.com 提供简体中文支持" - -#. Author of the plugin/theme -msgid "Ante Laca" -msgstr "Ante Laca" - -#. Author URI of the plugin/theme -msgid "https://www.antelaca.xyz" -msgstr "https://www.antelaca.xyz" - -#~ msgid "Cloudflare cache" -#~ msgstr "Cloudflare缓存" - -#~ msgid "Varnish" -#~ msgstr "Varnish 缓存" - -#~ msgid "If Varnish runs on your server, you need to activate this option." -#~ msgstr "如果Varnish在您的服务器上运行,则需要激活此选项。" - -#~ msgid "Part of the URL will also work" -#~ msgstr "包含这些网址部分的页面也一样生效" - -#~ msgid "Exclude image" -#~ msgstr "排除图片" - -#~ msgid "This page is affected by URL(s) exclude options on Images page" -#~ msgstr "此页面受图片页面上网址排除选项的影响" - -#~ msgid "settings" -#~ msgstr "设置" - -#~ msgid "Enable auto purge" -#~ msgstr "启用自动清除" - -#~ msgid "Prefetch external CSS resources" -#~ msgstr "预加载外部 CSS 资源" - -#~ msgid "Cron tasks" -#~ msgstr "定时任务" - -#~ msgid "Prefetch external JS resources" -#~ msgstr "预加载外部 JS 资源" - -#~ msgid "Error" -#~ msgstr "错误" - -#~ msgid "Warning" -#~ msgstr "警告" - -#~ msgid "Notice" -#~ msgstr "通知" - -#~ msgid "Event" -#~ msgstr "活动" diff --git a/languages/wpp.pot b/languages/wpp.pot index 0bcfbe4..e84c506 100644 --- a/languages/wpp.pot +++ b/languages/wpp.pot @@ -1,1323 +1,1709 @@ -#, fuzzy +# Copyright (C) 2026 Ante Laca +# This file is distributed under the GPL-2.0-or-later. msgid "" msgstr "" -"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" -"Project-Id-Version: WP Performance\n" -"POT-Creation-Date: 2019-08-30 14:57+0200\n" -"PO-Revision-Date: 2018-12-26 17:50+0100\n" -"Last-Translator: \n" -"Language-Team: \n" +"Project-Id-Version: WP Performance 2.0.0\n" +"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/WP-Performance\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: Poedit 2.0.3\n" -"X-Poedit-Basepath: ..\n" -"X-Poedit-Flags-xgettext: --add-comments=translators:\n" -"X-Poedit-WPHeader: wp-performance.php\n" -"X-Poedit-SourceCharset: UTF-8\n" -"X-Poedit-KeywordsList: __;_e;_n:1,2;_x:1,2c;_ex:1,2c;_nx:4c,1,2;esc_attr__;" -"esc_attr_e;esc_attr_x:1,2c;esc_html__;esc_html_e;esc_html_x:1,2c;_n_noop:1,2;" -"_nx_noop:3c,1,2;__ngettext_noop:1,2;wpp_notify\n" -"X-Poedit-SearchPath-0: .\n" -"X-Poedit-SearchPath-1: vendor\n" -"X-Poedit-SearchPath-2: .git\n" -"X-Poedit-SearchPath-3: assets\n" -"X-Poedit-SearchPathExcluded-0: *.js\n" +"POT-Creation-Date: 2026-08-18T12:27:44+00:00\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"X-Generator: WP-CLI 2.12.0\n" +"X-Domain: wpp\n" + +#. Plugin Name of the plugin +#: wp-performance.php +#: src/Admin/AdminMenu.php:23 +#: src/Admin/AdminMenu.php:24 +#: src/Admin/Metabox.php:37 +#: assets/admin/app/App.jsx:85 +msgid "WP Performance" +msgstr "" + +#. Description of the plugin +#: wp-performance.php +msgid "WP Performance Optimizer - cache & performance plugin." +msgstr "" + +#. Author of the plugin +#: wp-performance.php +msgid "Ante Laca" +msgstr "" + +#: src/Addons/Cloudflare/CloudflareApi.php:58 +msgid "Unknown Cloudflare error." +msgstr "" + +#: src/Addons/Cloudflare/CloudflareController.php:113 +msgid "Cloudflare rejected the request." +msgstr "" + +#: src/Addons/Cloudflare/CloudflareController.php:120 +msgid "Cloudflare is not configured." +msgstr "" + +#: src/Admin/CompatibilityNotice.php:63 +msgid "WP Performance detected another caching/optimization plugin:" +msgstr "" + +#: src/Admin/CompatibilityNotice.php:65 +msgid "Running more than one can cause conflicts; consider deactivating the others." +msgstr "" + +#: src/Admin/Metabox.php:54 +msgid "Exclude from cache" +msgstr "" + +#: src/Admin/Metabox.php:55 +msgid "Exclude from CSS optimization" +msgstr "" + +#: src/Admin/Metabox.php:56 +msgid "Exclude from JavaScript optimization" +msgstr "" + +#: src/Admin/Metabox.php:57 +msgid "Exclude from HTML optimization" +msgstr "" + +#: src/Admin/Metabox.php:58 +msgid "Exclude from image optimization" +msgstr "" + +#: src/Admin/Metabox.php:59 +msgid "Exclude from video lazy load" +msgstr "" + +#: src/Cron/CronHooks.php:45 +msgid "Once weekly" +msgstr "" + +#: src/Cron/CronHooks.php:46 +msgid "Once monthly" +msgstr "" + +#: src/Rest/Admin/FilesController.php:77 +msgid "Could not load the homepage automatically, so the list may be incomplete. Visit your site once, then reload this page." +msgstr "" + +#: src/Rest/Admin/FilesController.php:82 +msgid "No files were found. Turn on a CSS or JavaScript optimization first, then update the list." +msgstr "" + +#: src/Rest/Admin/OverviewController.php:98 +#: src/Rest/Admin/OverviewController.php:124 +#: src/Rest/Admin/OverviewController.php:126 +#: src/Rest/Admin/OverviewController.php:128 +msgid "Page cache" +msgstr "" + +#: src/Rest/Admin/OverviewController.php:99 +#: assets/admin/app/tabs/CacheTab.jsx:240 +#: assets/admin/app/tabs/CacheTab.jsx:270 +msgid "Block cache" +msgstr "" + +#: src/Rest/Admin/OverviewController.php:100 +#: assets/admin/app/tabs/CacheTab.jsx:220 +msgid "Browser caching" +msgstr "" + +#: src/Rest/Admin/OverviewController.php:101 +msgid "GZIP compression" +msgstr "" + +#: src/Rest/Admin/OverviewController.php:102 +msgid "CSS optimization" +msgstr "" + +#: src/Rest/Admin/OverviewController.php:103 +msgid "JavaScript optimization" +msgstr "" -#: includes/addons/cloudflare/cloudflare.php:55 -msgid "Cloudflare - purge everything" +#: src/Rest/Admin/OverviewController.php:104 +msgid "HTML minification" msgstr "" -#: includes/addons/cloudflare/cloudflare.php:56 -msgid "Cloudflare - purge custom URL(s)" +#: src/Rest/Admin/OverviewController.php:105 +msgid "Lazy loading" msgstr "" -#: includes/addons/cloudflare/cloudflare.php:97 -msgid "Cloudflare API credentials not set" +#: src/Rest/Admin/OverviewController.php:106 +msgid "WebP/AVIF images" msgstr "" -#: includes/addons/cloudflare/cloudflare.php:116 -msgid " Cloudflare cannot get zone details. Check your Cloudflare credentials" +#: src/Rest/Admin/OverviewController.php:107 +msgid "Database cleanup" msgstr "" -#: includes/addons/cloudflare/cloudflare.php:123 +#: src/Rest/Admin/OverviewController.php:108 +#: assets/admin/app/App.jsx:43 +#: assets/admin/app/tabs/SettingsTab.jsx:22 +msgid "CDN" +msgstr "" + +#: src/Rest/Admin/OverviewController.php:109 +#: src/Rest/Admin/OverviewController.php:133 +#: src/Rest/Admin/OverviewController.php:135 +#: src/Rest/Admin/OverviewController.php:137 +#: src/Rest/Admin/OverviewController.php:139 +#: assets/admin/app/tabs/SettingsTab.jsx:211 +msgid "Object cache" +msgstr "" + +#: src/Rest/Admin/OverviewController.php:124 +msgid "Page caching is turned off." +msgstr "" + +#: src/Rest/Admin/OverviewController.php:126 +msgid "Page caching is active and serving cached pages." +msgstr "" + +#: src/Rest/Admin/OverviewController.php:128 +msgid "The advanced-cache.php drop-in or WP_CACHE constant is missing." +msgstr "" + +#: src/Rest/Admin/OverviewController.php:133 +msgid "A persistent object cache is active." +msgstr "" + +#: src/Rest/Admin/OverviewController.php:135 +msgid "Another object cache drop-in is installed." +msgstr "" + +#: src/Rest/Admin/OverviewController.php:137 +msgid "Redis is available but the object cache is not enabled." +msgstr "" + +#: src/Rest/Admin/OverviewController.php:139 +msgid "No object cache backend detected (Redis recommended)." +msgstr "" + +#: src/Rest/Admin/OverviewController.php:144 +#: src/Rest/Admin/OverviewController.php:145 +msgid "Compression" +msgstr "" + +#: src/Rest/Admin/OverviewController.php:144 +msgid "GZIP compression is available." +msgstr "" + +#: src/Rest/Admin/OverviewController.php:145 +msgid "The zlib extension is missing, so GZIP is unavailable." +msgstr "" + +#: src/Rest/Admin/OverviewController.php:154 +#: src/Rest/Admin/OverviewController.php:155 +msgid "PHP OPcache" +msgstr "" + +#: src/Rest/Admin/OverviewController.php:154 +msgid "OPcache is enabled." +msgstr "" + +#: src/Rest/Admin/OverviewController.php:155 +msgid "OPcache is not enabled. Enabling it speeds up PHP execution." +msgstr "" + +#. translators: %s: PHP version. +#: src/Rest/Admin/OverviewController.php:159 +#: src/Rest/Admin/OverviewController.php:160 +msgid "PHP version" +msgstr "" + +#. translators: %s: PHP version. +#: src/Rest/Admin/OverviewController.php:159 #, php-format -msgid "" -" Cloudflare zone %s is not activated. Please go to your Cloudflare dashboard " -"and activate it." +msgid "Running PHP %s." msgstr "" -#: includes/addons/cloudflare/cloudflare.php:127 +#. translators: 1: current PHP version, 2: recommended version. +#: src/Rest/Admin/OverviewController.php:160 #, php-format -msgid "" -" Cloudflare zone %s status is pending and these settings won't have any " -"effect on your website." +msgid "PHP %1$s is below the recommended %2$s." msgstr "" -#: includes/addons/cloudflare/cloudflare.php:142 -msgid " Cloudflare development mode not set" +#: src/Rest/Admin/OverviewController.php:166 +#: src/Rest/Admin/OverviewController.php:167 +msgid "Cache directory" msgstr "" -#: includes/addons/cloudflare/cloudflare.php:151 -msgid " Cloudflare cache level not set" +#: src/Rest/Admin/OverviewController.php:166 +msgid "The cache directory is writable." msgstr "" -#: includes/addons/cloudflare/cloudflare.php:161 -msgid " Cloudflare browser cache expiration not set" +#: src/Rest/Admin/OverviewController.php:167 +msgid "The cache directory is not writable." msgstr "" -#: includes/addons/cloudflare/cloudflare.php:175 -msgid " Cloudflare minify not set" +#: src/Rest/Admin/OverviewController.php:171 +#: src/Rest/Admin/OverviewController.php:172 +msgid "Image conversion" msgstr "" -#: includes/addons/cloudflare/cloudflare.php:187 -msgid " Cloudflare Rocket loader mode not set" +#: src/Rest/Admin/OverviewController.php:171 +msgid "GD can generate WebP images." msgstr "" -#: includes/addons/cloudflare/cloudflare.php:197 -msgid " Cloudflare Brotli mode not set" +#: src/Rest/Admin/OverviewController.php:172 +msgid "GD cannot generate WebP images on this server." msgstr "" -#: includes/addons/cloudflare/cloudflare.php:209 -msgid "Cloudflare settings saved" +#: src/Rest/Admin/OverviewController.php:179 +#: src/Rest/Admin/OverviewController.php:180 +#: src/Rest/Admin/OverviewController.php:182 +#: src/Rest/Admin/OverviewController.php:184 +msgid "Server rules" msgstr "" -#: includes/addons/cloudflare/cloudflare.php:231 -msgid "Something went wrong. Cannot purge Cloudflare cache" +#: src/Rest/Admin/OverviewController.php:179 +msgid "Apache detected; .htaccess is writable." msgstr "" -#: includes/addons/cloudflare/cloudflare.php:261 -msgid "Something went wrong. Cannot purge Cloudflare custom URL(s) cache" +#: src/Rest/Admin/OverviewController.php:180 +msgid "Apache detected but .htaccess is not writable." msgstr "" -#: includes/addons/cloudflare/views/addon.php:20 -msgid "Integrate your Cloudflare account with this add-on." +#: src/Rest/Admin/OverviewController.php:182 +msgid "Nginx detected; add the generated rules from Settings." msgstr "" -#: includes/addons/cloudflare/views/addon.php:27 -#: includes/addons/cloudflare/views/admin.php:82 -#: includes/addons/cloudflare/views/admin.php:175 -#: includes/addons/cloudflare/views/admin.php:187 -#: includes/addons/prefetch/views/addon.php:18 -#: includes/addons/varnish/views/addon.php:49 includes/functions/admin.php:267 -#: includes/functions/backend.php:238 -msgid "Enable" +#: src/Rest/Admin/OverviewController.php:184 +msgid "Server type could not be determined." msgstr "" -#: includes/addons/cloudflare/views/admin.php:15 -msgid "Caching" +#: src/Rest/Admin/SettingsController.php:64 +#: src/Rest/Admin/SettingsController.php:73 +msgid "Unknown settings group." +msgstr "" + +#: assets/admin/app/App.jsx:36 +msgid "Overview" msgstr "" -#: includes/addons/cloudflare/views/admin.php:21 -msgid "Purge Cache" +#: assets/admin/app/App.jsx:37 +#: assets/admin/app/tabs/SettingsTab.jsx:16 +#: assets/blocks/cache/index.js:8 +msgid "Cache" msgstr "" -#: includes/addons/cloudflare/views/admin.php:23 -msgid "Clear all Cloudflare cache" +#: assets/admin/app/App.jsx:38 +#: assets/admin/app/tabs/SettingsTab.jsx:17 +msgid "CSS" msgstr "" -#: includes/addons/cloudflare/views/admin.php:23 -msgid "Purge everything" +#: assets/admin/app/App.jsx:39 +#: assets/admin/app/tabs/SettingsTab.jsx:18 +msgid "JavaScript" +msgstr "" + +#: assets/admin/app/App.jsx:40 +#: assets/admin/app/tabs/SettingsTab.jsx:19 +msgid "HTML" +msgstr "" + +#: assets/admin/app/App.jsx:41 +#: assets/admin/app/tabs/SettingsTab.jsx:20 +msgid "Media" +msgstr "" + +#: assets/admin/app/App.jsx:42 +#: assets/admin/app/tabs/SettingsTab.jsx:21 +msgid "Database" +msgstr "" + +#: assets/admin/app/App.jsx:44 +#: assets/admin/app/tabs/SettingsTab.jsx:23 +msgid "Settings" +msgstr "" + +#: assets/admin/app/App.jsx:45 +msgid "Add-ons" +msgstr "" + +#: assets/admin/app/App.jsx:51 +#: assets/admin/app/tabs/AddonsTab.jsx:60 +#: assets/admin/app/tabs/SettingsTab.jsx:24 +msgid "Cloudflare" +msgstr "" + +#: assets/admin/app/components/ConfirmDialog.jsx:72 +msgid "Are you sure?" msgstr "" -#: includes/addons/cloudflare/views/admin.php:24 -msgid "Clear custom URL(s) from Cloudflare cache" +#: assets/admin/app/components/ConfirmDialog.jsx:103 +#: assets/admin/app/components/ImageSizes.jsx:176 +msgid "Cancel" msgstr "" -#: includes/addons/cloudflare/views/admin.php:24 -#: includes/addons/cloudflare/views/admin.php:29 -msgid "Purge custom URL(s)" +#: assets/admin/app/components/ConfirmDialog.jsx:111 +msgid "Confirm" msgstr "" -#: includes/addons/cloudflare/views/admin.php:49 includes/admin/cache.php:116 -#: includes/admin/cache.php:335 includes/admin/cache.php:355 -#: includes/admin/cache.php:414 includes/admin/cdn.php:66 -#: includes/admin/css.php:317 includes/admin/css.php:327 -#: includes/admin/includes/external_files.php:66 -#: includes/admin/includes/external_files.php:94 -#: includes/admin/includes/local_files.php:65 -#: includes/admin/includes/local_files.php:92 includes/admin/javascript.php:243 -#: includes/admin/javascript.php:253 includes/admin/media.php:66 -#: includes/admin/media.php:92 includes/admin/media.php:136 -#: includes/admin/media.php:156 includes/admin/media.php:238 -#: includes/admin/media.php:258 includes/functions/miscellaneous.php:258 +#: assets/admin/app/components/fields/RepeatableInput.jsx:11 +#: assets/admin/app/components/ImageSizes.jsx:173 +#: assets/admin/app/tabs/JsTab.jsx:77 +msgid "Add" +msgstr "" + +#: assets/admin/app/components/fields/RepeatableInput.jsx:37 +#: assets/admin/app/components/ImageSizes.jsx:47 +#: assets/admin/app/components/ImageSizes.jsx:131 msgid "Remove" msgstr "" -#: includes/addons/cloudflare/views/admin.php:58 -#: includes/addons/cloudflare/views/admin.php:67 -msgid "" -"Any assets in the Cloudflare cache that match the URL(s) exactly will be " -"purged from the cache." +#: assets/admin/app/components/FileListTable.jsx:8 +msgid "Theme" +msgstr "" + +#: assets/admin/app/components/FileListTable.jsx:9 +msgid "Plugins" +msgstr "" + +#: assets/admin/app/components/FileListTable.jsx:10 +msgid "External" +msgstr "" + +#: assets/admin/app/components/FileListTable.jsx:14 +msgid "Everywhere" +msgstr "" + +#: assets/admin/app/components/FileListTable.jsx:15 +msgid "Only on selected URLs" +msgstr "" + +#: assets/admin/app/components/FileListTable.jsx:16 +msgid "Everywhere except selected URLs" +msgstr "" + +#: assets/admin/app/components/FileListTable.jsx:35 +msgid "No files collected yet. Enable caching or an optimization, visit your site, then choose \"Update files list\"." +msgstr "" + +#: assets/admin/app/components/FileListTable.jsx:75 +msgid "File" +msgstr "" + +#: assets/admin/app/components/FileListTable.jsx:76 +#: assets/admin/app/tabs/HtmlTab.jsx:45 +msgid "Minify" +msgstr "" + +#: assets/admin/app/components/FileListTable.jsx:77 +msgid "Inline" +msgstr "" + +#: assets/admin/app/components/FileListTable.jsx:78 +msgid "Combine" +msgstr "" + +#: assets/admin/app/components/FileListTable.jsx:79 +msgid "Disable" msgstr "" -#: includes/addons/cloudflare/views/admin.php:70 includes/admin/cache.php:380 -#: includes/admin/css.php:351 includes/admin/includes/external_files.php:113 -#: includes/admin/includes/external_files.php:124 -#: includes/admin/includes/local_files.php:109 -#: includes/admin/includes/local_files.php:120 -#: includes/admin/javascript.php:277 includes/admin/media.php:180 -#: includes/admin/media.php:282 includes/functions/miscellaneous.php:260 +#: assets/admin/app/components/FileListTable.jsx:84 +msgid "Apply to all" +msgstr "" + +#: assets/admin/app/components/FileListTable.jsx:125 +#: assets/admin/app/components/FileListTable.jsx:132 +#: assets/admin/app/tabs/AddonsTab.jsx:130 +#: assets/admin/app/tabs/CacheTab.jsx:102 +#: assets/admin/app/tabs/CloudflareTab.jsx:104 +#: assets/admin/app/tabs/CssTab.jsx:160 +#: assets/admin/app/tabs/HtmlTab.jsx:26 +#: assets/admin/app/tabs/JsTab.jsx:96 +#: assets/admin/app/tabs/MediaTab.jsx:166 +#: assets/admin/app/tabs/MediaTab.jsx:183 msgid "Add URL" msgstr "" -#: includes/addons/cloudflare/views/admin.php:78 -msgid "Development mode" +#: assets/admin/app/components/ImageSizes.jsx:36 +msgid "Image size added." msgstr "" -#: includes/addons/cloudflare/views/admin.php:85 -msgid "Temporarily activate development mode on your website." +#: assets/admin/app/components/ImageSizes.jsx:38 +msgid "Could not add size." msgstr "" -#: includes/addons/cloudflare/views/admin.php:86 -msgid "This setting will automatically turn off after 3 hours." +#: assets/admin/app/components/ImageSizes.jsx:45 +msgid "Remove image size" msgstr "" -#: includes/addons/cloudflare/views/admin.php:91 -msgid "Cache level" +#: assets/admin/app/components/ImageSizes.jsx:46 +msgid "New uploads will no longer be generated at this size." msgstr "" -#: includes/addons/cloudflare/views/admin.php:94 -msgid "Aggressive - Standard" +#: assets/admin/app/components/ImageSizes.jsx:56 +msgid "Could not remove size." msgstr "" -#: includes/addons/cloudflare/views/admin.php:95 -msgid "Simplified - Ignore query string" +#: assets/admin/app/components/ImageSizes.jsx:63 +#: assets/admin/app/components/ImageSizes.jsx:185 +msgid "Restore defaults" msgstr "" -#: includes/addons/cloudflare/views/admin.php:96 -msgid "Basic - No query string" +#: assets/admin/app/components/ImageSizes.jsx:64 +msgid "This restores the WordPress default image sizes and discards your changes here." msgstr "" -#: includes/addons/cloudflare/views/admin.php:101 -msgid "" -"Aggressive: Delivers a different resource each time the query string changes." +#: assets/admin/app/components/ImageSizes.jsx:65 +#: assets/admin/app/tabs/SettingsTab.jsx:71 +#: assets/admin/app/tabs/SettingsTab.jsx:158 +msgid "Restore" msgstr "" -#: includes/addons/cloudflare/views/admin.php:102 -msgid "" -"Simplified: Delivers the same resource to everyone independent of the query " -"string." +#: assets/admin/app/components/ImageSizes.jsx:71 +msgid "Defaults restored." msgstr "" -#: includes/addons/cloudflare/views/admin.php:103 -msgid "" -"Basic: Only delivers resources from cache when there is no query string." +#: assets/admin/app/components/ImageSizes.jsx:77 +#: assets/admin/app/components/ImageSizes.jsx:194 +msgid "Regenerate thumbnails" msgstr "" -#: includes/addons/cloudflare/views/admin.php:118 -msgid "Browser Cache Expiration" +#: assets/admin/app/components/ImageSizes.jsx:78 +msgid "Every image is processed again. This may take a while on large media libraries." msgstr "" -#: includes/addons/cloudflare/views/admin.php:121 -msgid "Respect Existing Headers" +#: assets/admin/app/components/ImageSizes.jsx:79 +msgid "Regenerate" msgstr "" -#: includes/addons/cloudflare/views/admin.php:131 -msgid "" -"Browser cache TTL (in seconds) specifies how long CloudFlare-cached " -"resources will remain on your visitors computers." +#: assets/admin/app/components/ImageSizes.jsx:98 +msgid "Thumbnails regenerated." msgstr "" -#: includes/addons/cloudflare/views/admin.php:132 -msgid "The minimum TTL available depends on the plan level of the zone." +#: assets/admin/app/components/ImageSizes.jsx:100 +msgid "Regeneration failed." msgstr "" -#: includes/addons/cloudflare/views/admin.php:140 -msgid "Content" +#: assets/admin/app/components/ImageSizes.jsx:113 +msgid "Name" msgstr "" -#: includes/addons/cloudflare/views/admin.php:146 includes/admin/css.php:27 -#: includes/admin/includes/local_files.php:153 includes/admin/javascript.php:27 -msgid "Minify" +#: assets/admin/app/components/ImageSizes.jsx:114 +msgid "W" msgstr "" -#: includes/addons/cloudflare/views/admin.php:171 -msgid "Rocket Loader" +#: assets/admin/app/components/ImageSizes.jsx:115 +msgid "H" msgstr "" -#: includes/addons/cloudflare/views/admin.php:178 -msgid "Rocket Loader is a asynchronous JavaScript loader." +#: assets/admin/app/components/ImageSizes.jsx:116 +#: assets/admin/app/components/ImageSizes.jsx:170 +msgid "Crop" msgstr "" -#: includes/addons/cloudflare/views/admin.php:183 -msgid "Brotli" +#: assets/admin/app/components/ImageSizes.jsx:126 +msgid "Yes" msgstr "" -#: includes/addons/cloudflare/views/admin.php:190 -msgid "" -"Speed up page load times for your visitor’s HTTPS traffic by applying Brotli " -"compression." +#: assets/admin/app/components/ImageSizes.jsx:146 +msgid "name" msgstr "" -#: includes/addons/cloudflare/views/admin.php:198 includes/admin/addons.php:17 -#: includes/admin/cache.php:259 includes/admin/cdn.php:33 -#: includes/admin/css.php:119 includes/admin/database.php:183 -#: includes/admin/javascript.php:118 includes/admin/media.php:292 -#: includes/admin/settings.php:81 +#: assets/admin/app/components/ImageSizes.jsx:182 +msgid "Add size" +msgstr "" + +#: assets/admin/app/components/ImageSizes.jsx:193 +msgid "Regenerating" +msgstr "" + +#: assets/admin/app/components/SaveButton.jsx:12 +msgid "Saving…" +msgstr "" + +#: assets/admin/app/components/SaveButton.jsx:12 msgid "Save changes" msgstr "" -#: includes/addons/cloudflare/views/admin.php:207 -msgid "Cloudflare credentials" +#: assets/admin/app/hooks/useSettingsGroup.js:62 +msgid "Settings saved." msgstr "" -#: includes/addons/cloudflare/views/admin.php:211 -msgid "API key" +#: assets/admin/app/hooks/useSettingsGroup.js:65 +msgid "Could not save settings." msgstr "" -#: includes/addons/cloudflare/views/admin.php:218 -msgid "Account email" +#: assets/admin/app/lib/format.js:6 +msgid "just now" msgstr "" -#: includes/addons/cloudflare/views/admin.php:223 -msgid "Zone ID" +#. translators: %d: number of minutes. +#: assets/admin/app/lib/format.js:11 +#, js-format +msgid "%d minute ago" +msgid_plural "%d minutes ago" +msgstr[0] "" +msgstr[1] "" + +#. translators: %d: number of hours. +#: assets/admin/app/lib/format.js:16 +#, js-format +msgid "%d hour ago" +msgid_plural "%d hours ago" +msgstr[0] "" +msgstr[1] "" + +#. translators: %d: number of days. +#: assets/admin/app/lib/format.js:20 +#, js-format +msgid "%d day ago" +msgid_plural "%d days ago" +msgstr[0] "" +msgstr[1] "" + +#: assets/admin/app/tabs/AddonsTab.jsx:13 +msgid "Prerender (load the whole page, instant)" +msgstr "" + +#: assets/admin/app/tabs/AddonsTab.jsx:14 +msgid "Prefetch (fetch the page, lighter)" +msgstr "" + +#: assets/admin/app/tabs/AddonsTab.jsx:18 +msgid "On click" msgstr "" -#: includes/addons/prefetch/views/addon.php:9 -#: includes/addons/prefetch/views/addon.php:18 -msgid "Dynamic page preload" +#: assets/admin/app/tabs/AddonsTab.jsx:19 +msgid "On hover" msgstr "" -#: includes/addons/prefetch/views/addon.php:12 -msgid "Preloads a page right before a user clicks on link" +#: assets/admin/app/tabs/AddonsTab.jsx:20 +msgid "As soon as possible" msgstr "" -#: includes/addons/varnish/views/addon.php:20 -msgid "If Varnish runs on your server, you must activate this add-on." +#: assets/admin/app/tabs/AddonsTab.jsx:64 +msgid "Integrate your Cloudflare account to purge cache and manage zone settings." msgstr "" -#: includes/addons/varnish/views/addon.php:28 +#: assets/admin/app/tabs/AddonsTab.jsx:73 +msgid "Configure Cloudflare" +msgstr "" + +#: assets/admin/app/tabs/AddonsTab.jsx:80 +#: assets/admin/app/tabs/SettingsTab.jsx:25 +msgid "Varnish" +msgstr "" + +#: assets/admin/app/tabs/AddonsTab.jsx:84 +msgid "Automatically purge Varnish whenever the cache is cleared." +msgstr "" + +#: assets/admin/app/tabs/AddonsTab.jsx:88 msgid "Custom host" msgstr "" -#: includes/addons/varnish/views/addon.php:41 -msgid "If you are using proxy, you may need this option" +#: assets/admin/app/tabs/AddonsTab.jsx:100 +msgid "Link prefetch" msgstr "" -#: includes/admin/addons.php:27 includes/admin/admin.php:30 -#: includes/admin/admin.php:45 includes/functions/admin.php:236 -#: includes/functions/admin.php:240 -msgid "Add-ons" +#: assets/admin/app/tabs/AddonsTab.jsx:104 +msgid "Loads the next page in the background before a visitor clicks, so navigation feels instant. Uses the Speculation Rules API." msgstr "" -#: includes/admin/addons.php:31 -#, php-format -msgid "Add more features to %s with add-ons." +#: assets/admin/app/tabs/AddonsTab.jsx:109 +msgid "Mode" msgstr "" -#: includes/admin/admin.php:23 includes/admin/admin.php:38 -#: includes/functions/admin.php:166 -msgid "Cache" +#: assets/admin/app/tabs/AddonsTab.jsx:117 +msgid "When to start" msgstr "" -#: includes/admin/admin.php:26 includes/admin/admin.php:41 -#: includes/functions/admin.php:196 includes/functions/admin.php:200 -msgid "Media" +#: assets/admin/app/tabs/AddonsTab.jsx:125 +msgid "Exclude URLs" msgstr "" -#: includes/admin/admin.php:27 includes/admin/admin.php:42 -#: includes/functions/admin.php:206 includes/functions/admin.php:210 -msgid "Database" +#: assets/admin/app/tabs/CacheTab.jsx:19 +msgid "Minutes" msgstr "" -#: includes/admin/admin.php:29 includes/admin/admin.php:44 -#: includes/admin/settings.php:12 includes/functions/admin.php:170 -#: includes/functions/admin.php:226 includes/functions/admin.php:230 -#: includes/functions/admin.php:290 -msgid "Settings" +#: assets/admin/app/tabs/CacheTab.jsx:20 +msgid "Hours" msgstr "" -#: includes/admin/cache.php:11 -msgid "Enable cache" +#: assets/admin/app/tabs/CacheTab.jsx:21 +msgid "Days" msgstr "" -#: includes/admin/cache.php:15 -msgid "Reduces your server response time by serving static files to users" +#: assets/admin/app/tabs/CacheTab.jsx:24 +#: assets/admin/app/tabs/HtmlTab.jsx:11 +msgid "Use {numbers}, {letters}, {any} or {all} to match dynamic parts of a URL." msgstr "" -#: includes/admin/cache.php:30 includes/admin/cache.php:194 -#: includes/admin/cache.php:246 -msgid "" -"Your web site is running on a Nginx server and some additional steps may be " -"required in order to use this option." +#: assets/admin/app/tabs/CacheTab.jsx:45 +msgid "Block cache cleared." msgstr "" -#: includes/admin/cache.php:39 -msgid "Separate cache for mobile devices" +#: assets/admin/app/tabs/CacheTab.jsx:47 +msgid "Could not clear the block cache." msgstr "" -#: includes/admin/cache.php:42 -msgid "Create a dedicated cache file for mobile devices" +#: assets/admin/app/tabs/CacheTab.jsx:58 +#: assets/admin/app/tabs/OverviewTab.jsx:60 +msgid "Cache cleared." msgstr "" -#: includes/admin/cache.php:48 -msgid "Clear cache after" +#: assets/admin/app/tabs/CacheTab.jsx:60 +#: assets/admin/app/tabs/OverviewTab.jsx:62 +msgid "Could not clear the cache." +msgstr "" + +#: assets/admin/app/tabs/CacheTab.jsx:67 +msgid "HTML files" msgstr "" -#: includes/admin/cache.php:53 -msgid "minutes" +#: assets/admin/app/tabs/CacheTab.jsx:68 +msgid "CSS files" +msgstr "" + +#: assets/admin/app/tabs/CacheTab.jsx:69 +msgid "JavaScript files" msgstr "" -#: includes/admin/cache.php:56 -msgid "hours" +#: assets/admin/app/tabs/CacheTab.jsx:74 +msgid "Cache statistics" msgstr "" -#: includes/admin/cache.php:59 -msgid "days" +#: assets/admin/app/tabs/CacheTab.jsx:83 +msgid "Total" msgstr "" -#: includes/admin/cache.php:66 +#: assets/admin/app/tabs/CacheTab.jsx:93 +#: assets/admin/app/tabs/CacheTab.jsx:277 +#: assets/admin/app/tabs/OverviewTab.jsx:134 +msgid "Clearing…" +msgstr "" + +#: assets/admin/app/tabs/CacheTab.jsx:93 +#: assets/admin/app/tabs/OverviewTab.jsx:134 +msgid "Clear cache" +msgstr "" + +#: assets/admin/app/tabs/CacheTab.jsx:97 +msgid "Exclude URL(s) from cache" +msgstr "" + +#: assets/admin/app/tabs/CacheTab.jsx:107 +msgid "Exclude User Agent(s) from cache" +msgstr "" + +#: assets/admin/app/tabs/CacheTab.jsx:111 +msgid "Add User Agent" +msgstr "" + +#: assets/admin/app/tabs/CacheTab.jsx:117 +msgid "Exclude search engines" +msgstr "" + +#: assets/admin/app/tabs/CacheTab.jsx:118 +msgid "Google, Bing and other crawlers bypass the cache." +msgstr "" + +#: assets/admin/app/tabs/CacheTab.jsx:128 +msgid "Enable cache" +msgstr "" + +#: assets/admin/app/tabs/CacheTab.jsx:132 +msgid "Reduces server response time by serving static HTML files to visitors." +msgstr "" + +#: assets/admin/app/tabs/CacheTab.jsx:141 +msgid "Mobile cache" +msgstr "" + +#: assets/admin/app/tabs/CacheTab.jsx:145 +msgid "Separate cache for mobile devices" +msgstr "" + +#: assets/admin/app/tabs/CacheTab.jsx:149 +msgid "Clear cache after" +msgstr "" + +#: assets/admin/app/tabs/CacheTab.jsx:164 msgid "Clear cache when" msgstr "" -#: includes/admin/cache.php:70 -msgid "A new post or page is published or updated" +#: assets/admin/app/tabs/CacheTab.jsx:168 +msgid "A post or page is published or updated" msgstr "" -#: includes/admin/cache.php:75 +#: assets/admin/app/tabs/CacheTab.jsx:173 msgid "A post or page is deleted" msgstr "" -#: includes/admin/cache.php:80 -msgid "settings are saved" +#: assets/admin/app/tabs/CacheTab.jsx:178 +msgid "WP Performance settings are saved" msgstr "" -#: includes/admin/cache.php:86 +#: assets/admin/app/tabs/CacheTab.jsx:182 msgid "Clear cache options" msgstr "" -#: includes/admin/cache.php:90 -msgid "Keep generated CSS/JS files" +#: assets/admin/app/tabs/CacheTab.jsx:186 +msgid "Keep generated CSS/JS files when clearing the cache" +msgstr "" + +#: assets/admin/app/tabs/CacheTab.jsx:190 +msgid "Query strings" msgstr "" -#: includes/admin/cache.php:96 +#: assets/admin/app/tabs/CacheTab.jsx:194 +msgid "Cache URLs with query strings" +msgstr "" + +#: assets/admin/app/tabs/CacheTab.jsx:195 +msgid "Off (recommended): tracking params (utm, gclid, fbclid…) are ignored so only clean URLs are cached." +msgstr "" + +#: assets/admin/app/tabs/CacheTab.jsx:203 msgid "Cache preloading" msgstr "" -#: includes/admin/cache.php:126 includes/admin/cache.php:136 -msgid "Enter path to XML sitemap which will be used for cache preloading" +#: assets/admin/app/tabs/CacheTab.jsx:204 +msgid "Enter the path to an XML sitemap used to preload the cache." msgstr "" -#: includes/admin/cache.php:139 +#: assets/admin/app/tabs/CacheTab.jsx:213 msgid "Add Sitemap" msgstr "" -#: includes/admin/cache.php:147 -msgid "Browser caching" +#: assets/admin/app/tabs/CacheTab.jsx:221 +msgid "Leverage browser caching" msgstr "" -#: includes/admin/cache.php:151 -msgid "Leverage browser caching" +#: assets/admin/app/tabs/CacheTab.jsx:225 +msgid "Sets HTTP expiry headers so returning visitors load resources from their browser." msgstr "" -#: includes/admin/cache.php:176 -msgid "" -"Setting an expiry date in the HTTP headers for static resources instructs " -"the browser to load previously downloaded resources from local disk rather " -"than over the network" +#: assets/admin/app/tabs/CacheTab.jsx:231 +msgid "Gzip compression" msgstr "" -#: includes/admin/cache.php:183 includes/admin/cache.php:235 -msgid "" -"This option is turned ON automatically for all sites in Wordpress multisite" +#: assets/admin/app/tabs/CacheTab.jsx:235 +msgid "Compresses resources before sending them to the browser." msgstr "" -#: includes/admin/cache.php:204 -msgid "Enable gzip compression" +#: assets/admin/app/tabs/CacheTab.jsx:241 +msgid "Enable block cache" msgstr "" -#: includes/admin/cache.php:228 -msgid "" -"Compressing resources with gzip reduce the number of bytes sent over the " -"network" +#: assets/admin/app/tabs/CacheTab.jsx:245 +msgid "Caches parts of a page so they load faster, even when the full page is not cached. Add a Cache block to a page to use it." msgstr "" -#: includes/admin/cache.php:268 -msgid "Cache statistics" +#: assets/admin/app/tabs/CacheTab.jsx:254 +msgid "Default cache time (seconds)" msgstr "" -#: includes/admin/cache.php:269 includes/functions/admin.php:155 -#: includes/functions/admin.php:160 -msgid "Clear cache" +#: assets/admin/app/tabs/CacheTab.jsx:262 +msgid "Clearing" msgstr "" -#: includes/admin/cache.php:291 -msgid "HTML files" +#: assets/admin/app/tabs/CacheTab.jsx:266 +msgid "Also clear it when I clear the page cache" msgstr "" -#: includes/admin/cache.php:294 -msgid "CSS files" +#: assets/admin/app/tabs/CacheTab.jsx:277 +msgid "Clear block cache" msgstr "" -#: includes/admin/cache.php:297 -msgid "JavaScript files" +#: assets/admin/app/tabs/CdnTab.jsx:18 +msgid "Exclude file(s) from CDN" msgstr "" -#: includes/admin/cache.php:302 -msgid "Total cache size" +#: assets/admin/app/tabs/CdnTab.jsx:23 +#: assets/admin/app/tabs/CssTab.jsx:91 +#: assets/admin/app/tabs/JsTab.jsx:56 +msgid "Add file" msgstr "" -#: includes/admin/cache.php:313 -msgid "Exclude URL(s) from cache" +#: assets/admin/app/tabs/CdnTab.jsx:26 +msgid "Use {numbers}, {letters} or {any} to match dynamic parts of a URL." msgstr "" -#: includes/admin/cache.php:334 includes/admin/css.php:316 -#: includes/admin/javascript.php:242 includes/admin/media.php:135 -#: includes/admin/media.php:237 -#, php-format -msgid "Remove %s from excluded URL(s)?" +#: assets/admin/app/tabs/CdnTab.jsx:34 +msgid "Enable CDN" msgstr "" -#: includes/admin/cache.php:365 includes/admin/cache.php:377 -#: includes/admin/cdn.php:75 includes/admin/cdn.php:86 -#: includes/admin/css.php:336 includes/admin/css.php:348 -#: includes/admin/javascript.php:262 includes/admin/javascript.php:274 -#: includes/admin/media.php:165 includes/admin/media.php:177 -#: includes/admin/media.php:267 includes/admin/media.php:279 -msgid "Use {numbers} to match only numbers" +#: assets/admin/app/tabs/CdnTab.jsx:38 +msgid "Rewrites static asset URLs (CSS, JavaScript, images) to your CDN hostname." msgstr "" -#: includes/admin/cache.php:366 includes/admin/cache.php:377 -#: includes/admin/cdn.php:76 includes/admin/cdn.php:86 -#: includes/admin/css.php:337 includes/admin/css.php:348 -#: includes/admin/javascript.php:263 includes/admin/javascript.php:274 -#: includes/admin/media.php:166 includes/admin/media.php:177 -#: includes/admin/media.php:268 includes/admin/media.php:279 -msgid "Use {letters} to match only letters" +#: assets/admin/app/tabs/CdnTab.jsx:46 +msgid "CDN hostname" msgstr "" -#: includes/admin/cache.php:367 includes/admin/cache.php:377 -#: includes/admin/cdn.php:77 includes/admin/cdn.php:86 -#: includes/admin/css.php:338 includes/admin/css.php:348 -#: includes/admin/javascript.php:264 includes/admin/javascript.php:274 -#: includes/admin/media.php:167 includes/admin/media.php:177 -#: includes/admin/media.php:269 includes/admin/media.php:279 -msgid "Use {any} to match any string" +#: assets/admin/app/tabs/CloudflareTab.jsx:16 +#: assets/admin/app/tabs/HtmlTab.jsx:54 +#: assets/admin/app/tabs/OverviewTab.jsx:36 +msgid "Aggressive" msgstr "" -#: includes/admin/cache.php:368 includes/admin/cache.php:377 -#: includes/admin/css.php:339 includes/admin/css.php:348 -#: includes/admin/javascript.php:265 includes/admin/javascript.php:274 -#: includes/admin/media.php:168 includes/admin/media.php:177 -#: includes/admin/media.php:270 includes/admin/media.php:279 -msgid "Use {all} to match all" +#: assets/admin/app/tabs/CloudflareTab.jsx:17 +msgid "Simplified (ignore query string)" msgstr "" -#: includes/admin/cache.php:392 -msgid "Exclude User Agent(s) from cache" +#: assets/admin/app/tabs/CloudflareTab.jsx:18 +msgid "Basic (no query string)" msgstr "" -#: includes/admin/cache.php:427 -msgid "Add User Agent" +#: assets/admin/app/tabs/CloudflareTab.jsx:34 +msgid "complete." msgstr "" -#: includes/admin/cache.php:437 -msgid "Exclude search engines" +#: assets/admin/app/tabs/CloudflareTab.jsx:36 +msgid "Cloudflare error." msgstr "" -#: includes/admin/cdn.php:12 -msgid "Enable CDN" +#: assets/admin/app/tabs/CloudflareTab.jsx:52 +msgid "Cloudflare rejected:" msgstr "" -#: includes/admin/cdn.php:16 -msgid "" -"All URL(s) of static files ( CSS, JavaScript and Images ) will be rewritten " -"to the CDN hostname you provide. " +#: assets/admin/app/tabs/CloudflareTab.jsx:58 +msgid "Respect existing headers" msgstr "" -#: includes/admin/cdn.php:23 -msgid "CDN hostname" +#: assets/admin/app/tabs/CloudflareTab.jsx:62 +msgid "Credentials" msgstr "" -#: includes/admin/cdn.php:43 -msgid "Exclude file(s) from CDN" +#: assets/admin/app/tabs/CloudflareTab.jsx:63 +msgid "Account email" msgstr "" -#: includes/admin/cdn.php:89 -msgid "Add file" +#: assets/admin/app/tabs/CloudflareTab.jsx:66 +msgid "API key" msgstr "" -#: includes/admin/css.php:26 includes/admin/javascript.php:26 -msgid "File" +#: assets/admin/app/tabs/CloudflareTab.jsx:69 +msgid "Zone ID" msgstr "" -#: includes/admin/css.php:28 includes/admin/includes/local_files.php:171 -#: includes/admin/javascript.php:28 -msgid "Inline" +#: assets/admin/app/tabs/CloudflareTab.jsx:77 +msgid "Purge cache" msgstr "" -#: includes/admin/css.php:29 includes/admin/includes/local_files.php:189 -#: includes/admin/javascript.php:29 -msgid "Combine" +#: assets/admin/app/tabs/CloudflareTab.jsx:83 +#: assets/admin/app/tabs/CloudflareTab.jsx:85 +msgid "Purge everything" msgstr "" -#: includes/admin/css.php:30 includes/admin/includes/external_files.php:152 -#: includes/admin/includes/local_files.php:213 includes/admin/javascript.php:30 -msgid "Disable" +#: assets/admin/app/tabs/CloudflareTab.jsx:85 +msgid "Purging…" msgstr "" -#: includes/admin/css.php:37 includes/admin/javascript.php:37 -msgid "Update all files in list below" +#: assets/admin/app/tabs/CloudflareTab.jsx:92 +#: assets/admin/app/tabs/CloudflareTab.jsx:97 +msgid "Purge custom URLs" msgstr "" -#: includes/admin/css.php:47 includes/admin/javascript.php:47 -msgid "Theme" +#: assets/admin/app/tabs/CloudflareTab.jsx:100 +msgid "Custom URLs to purge" msgstr "" -#: includes/admin/css.php:69 includes/admin/javascript.php:69 -msgid "Plugins" +#: assets/admin/app/tabs/CloudflareTab.jsx:109 +msgid "Zone settings" msgstr "" -#: includes/admin/css.php:92 includes/admin/javascript.php:92 -msgid "External resources" +#: assets/admin/app/tabs/CloudflareTab.jsx:110 +msgid "Development mode" msgstr "" -#: includes/admin/css.php:115 includes/admin/javascript.php:114 -msgid "" -"If some of the files are missing from this list, enable Cache preloading " -"option." +#: assets/admin/app/tabs/CloudflareTab.jsx:114 +msgid "Temporarily bypass the Cloudflare cache (auto-off after 3h)" msgstr "" -#: includes/admin/css.php:122 includes/admin/javascript.php:121 -#, php-format -msgid "Clear collected %s files list.%s This option will also clear the cache." +#: assets/admin/app/tabs/CloudflareTab.jsx:117 +msgid "Cache level" msgstr "" -#: includes/admin/css.php:125 includes/admin/javascript.php:124 -msgid "Update files list" +#: assets/admin/app/tabs/CloudflareTab.jsx:120 +msgid "Browser cache TTL" msgstr "" -#: includes/admin/css.php:130 -msgid "CSS files not found" +#: assets/admin/app/tabs/CloudflareTab.jsx:127 +msgid "Rocket Loader" msgstr "" -#: includes/admin/css.php:134 includes/admin/javascript.php:133 -msgid "Reload" +#: assets/admin/app/tabs/CloudflareTab.jsx:128 +msgid "Asynchronous JavaScript loading" msgstr "" -#: includes/admin/css.php:142 +#: assets/admin/app/tabs/CloudflareTab.jsx:130 +msgid "Brotli" +msgstr "" + +#: assets/admin/app/tabs/CloudflareTab.jsx:131 +msgid "Brotli compression" +msgstr "" + +#: assets/admin/app/tabs/CssTab.jsx:19 +msgid "Default" +msgstr "" + +#: assets/admin/app/tabs/CssTab.jsx:41 +#: assets/admin/app/tabs/JsTab.jsx:30 +msgid "File list updated." +msgstr "" + +#: assets/admin/app/tabs/CssTab.jsx:43 +#: assets/admin/app/tabs/JsTab.jsx:32 +msgid "Could not update the file list." +msgstr "" + +#: assets/admin/app/tabs/CssTab.jsx:51 msgid "CSS settings" msgstr "" -#: includes/admin/css.php:158 +#: assets/admin/app/tabs/CssTab.jsx:52 msgid "Minify inline CSS" msgstr "" -#: includes/admin/css.php:166 -msgid "Asynchronously load CSS" +#: assets/admin/app/tabs/CssTab.jsx:55 +msgid "Remove unused CSS" msgstr "" -#: includes/admin/css.php:176 includes/admin/css.php:178 -msgid "Show critical CSS" +#: assets/admin/app/tabs/CssTab.jsx:59 +msgid "Inline only used CSS; load the rest async" msgstr "" -#: includes/admin/css.php:177 includes/admin/css.php:178 -msgid "Hide critical CSS" +#: assets/admin/app/tabs/CssTab.jsx:60 +msgid "Heuristic: keeps rules whose classes/ids appear on the page. The full CSS still loads async as a fallback." msgstr "" -#: includes/admin/css.php:188 -msgid "Eliminates render-blocking CSS" +#: assets/admin/app/tabs/CssTab.jsx:68 +msgid "Used-CSS safelist" msgstr "" -#: includes/admin/css.php:194 -msgid "" -"Loading CSS asynchronously will produce FOUC effect (a Flash Of Unstyled " -"Content). In order to minimize the FOUC effect, use critical CSS path." +#: assets/admin/app/tabs/CssTab.jsx:69 +msgid "Selectors to always keep, e.g. classes toggled by JavaScript." msgstr "" -#: includes/admin/css.php:202 -msgid "Critical CSS path" +#: assets/admin/app/tabs/CssTab.jsx:74 +msgid "Add selector" msgstr "" -#: includes/admin/css.php:207 -msgid "Enter critical CSS path definitions" +#: assets/admin/app/tabs/CssTab.jsx:78 +msgid "Asynchronous CSS" msgstr "" -#: includes/admin/css.php:212 -msgid "Generate critical CSS path" +#: assets/admin/app/tabs/CssTab.jsx:82 +msgid "Load CSS without render-blocking" msgstr "" -#: includes/admin/css.php:227 -msgid "Combine Google Fonts" +#: assets/admin/app/tabs/CssTab.jsx:87 +msgid "Exclude from async" msgstr "" -#: includes/admin/css.php:232 -msgid "Load all google fonts in one HTTP request" +#: assets/admin/app/tabs/CssTab.jsx:95 +msgid "Critical CSS" msgstr "" -#: includes/admin/css.php:241 +#: assets/admin/app/tabs/CssTab.jsx:96 +msgid "Above-the-fold CSS, inlined and applied before the async stylesheet loads." +msgstr "" + +#: assets/admin/app/tabs/CssTab.jsx:107 +msgid "Google Fonts" +msgstr "" + +#: assets/admin/app/tabs/CssTab.jsx:111 +msgid "Combine Google Fonts into one request" +msgstr "" + +#: assets/admin/app/tabs/CssTab.jsx:116 +msgid "Host Google Fonts locally and preload them" +msgstr "" + +#: assets/admin/app/tabs/CssTab.jsx:119 +msgid "Font display" +msgstr "" + +#: assets/admin/app/tabs/CssTab.jsx:126 +#: assets/admin/app/tabs/JsTab.jsx:82 +msgid "Logged-in users" +msgstr "" + +#: assets/admin/app/tabs/CssTab.jsx:130 msgid "Disable CSS optimization for logged-in users" msgstr "" -#: includes/admin/css.php:252 includes/admin/javascript.php:178 -msgid "Resource Hints" +#: assets/admin/app/tabs/CssTab.jsx:135 +msgid "Resource hints" msgstr "" -#: includes/admin/css.php:259 includes/admin/javascript.php:185 -msgid "Origins" +#: assets/admin/app/tabs/CssTab.jsx:137 +msgid "DNS prefetch" msgstr "" -#: includes/admin/css.php:286 includes/admin/javascript.php:212 -msgid "DNS prefetching can make external resources load faster" +#: assets/admin/app/tabs/CssTab.jsx:138 +msgid "Origins to resolve early, e.g. https://fonts.gstatic.com" msgstr "" -#: includes/admin/css.php:287 includes/admin/javascript.php:213 -msgid "Preconnect can remove additional roundtrips and reduce request latency" +#: assets/admin/app/tabs/CssTab.jsx:143 +#: assets/admin/app/tabs/CssTab.jsx:150 +msgid "Add origin" msgstr "" -#: includes/admin/css.php:295 +#: assets/admin/app/tabs/CssTab.jsx:146 +msgid "Preconnect" +msgstr "" + +#: assets/admin/app/tabs/CssTab.jsx:155 msgid "Exclude URL(s) from CSS optimization" msgstr "" -#: includes/admin/database.php:30 includes/admin/database.php:35 -msgid "Delete all pages, posts and comments from trash" +#: assets/admin/app/tabs/CssTab.jsx:177 +#: assets/admin/app/tabs/JsTab.jsx:113 +msgid "Updating…" msgstr "" -#: includes/admin/database.php:31 includes/admin/database.php:55 -#: includes/admin/database.php:82 includes/admin/database.php:105 -#: includes/admin/database.php:132 includes/admin/database.php:157 -msgid "Delete" +#: assets/admin/app/tabs/CssTab.jsx:177 +#: assets/admin/app/tabs/JsTab.jsx:113 +msgid "Update files list" msgstr "" -#: includes/admin/database.php:34 -msgid "Trash" +#: assets/admin/app/tabs/DatabaseTab.jsx:15 +msgid "Not scheduled" msgstr "" -#: includes/admin/database.php:41 includes/admin/database.php:65 -#: includes/admin/database.php:92 includes/admin/database.php:115 -#: includes/admin/database.php:142 includes/admin/database.php:167 -msgid "Enable automatic cleanup" +#: assets/admin/app/tabs/DatabaseTab.jsx:16 +msgid "Daily" +msgstr "" + +#: assets/admin/app/tabs/DatabaseTab.jsx:17 +msgid "Weekly" +msgstr "" + +#: assets/admin/app/tabs/DatabaseTab.jsx:18 +msgid "Monthly" msgstr "" -#: includes/admin/database.php:54 includes/admin/database.php:59 -msgid "Delete all spam comments" +#: assets/admin/app/tabs/DatabaseTab.jsx:22 +msgid "Trash" +msgstr "" + +#: assets/admin/app/tabs/DatabaseTab.jsx:22 +msgid "Trashed posts and pages." msgstr "" -#: includes/admin/database.php:58 +#: assets/admin/app/tabs/DatabaseTab.jsx:23 msgid "Spam" msgstr "" -#: includes/admin/database.php:81 includes/admin/database.php:86 -msgid "Delete all revisions" +#: assets/admin/app/tabs/DatabaseTab.jsx:23 +msgid "Spam and trashed comments." msgstr "" -#: includes/admin/database.php:85 +#: assets/admin/app/tabs/DatabaseTab.jsx:24 msgid "Revisions" msgstr "" -#: includes/admin/database.php:104 includes/admin/database.php:109 -msgid "Delete all expired transients" +#: assets/admin/app/tabs/DatabaseTab.jsx:24 +msgid "Stored post revisions." msgstr "" -#: includes/admin/database.php:108 +#: assets/admin/app/tabs/DatabaseTab.jsx:25 msgid "Transients" msgstr "" -#: includes/admin/database.php:131 includes/admin/database.php:136 -msgid "Delete all auto drafts" +#: assets/admin/app/tabs/DatabaseTab.jsx:25 +msgid "Expired and stale transients." msgstr "" -#: includes/admin/database.php:135 +#: assets/admin/app/tabs/DatabaseTab.jsx:26 msgid "Auto Drafts" msgstr "" -#: includes/admin/database.php:156 includes/admin/database.php:161 -msgid "Delete all unused scheduled tasks" +#: assets/admin/app/tabs/DatabaseTab.jsx:26 +msgid "Auto-saved draft posts." msgstr "" -#: includes/admin/database.php:160 +#: assets/admin/app/tabs/DatabaseTab.jsx:27 msgid "Scheduled tasks" msgstr "" -#: includes/admin/database.php:179 -msgid "" -"Backup your database before running any of these cleanup actions. Once a " -"database cleanup has been performed, there is no way to undo it." +#: assets/admin/app/tabs/DatabaseTab.jsx:27 +msgid "Orphaned cron events." msgstr "" -#: includes/admin/database.php:185 includes/admin/database.php:186 -msgid "Delete all" +#: assets/admin/app/tabs/DatabaseTab.jsx:53 +msgid "Run cleanup" msgstr "" -#: includes/admin/database.php:194 -msgid "Automatic database cleanup" +#: assets/admin/app/tabs/DatabaseTab.jsx:54 +msgid "This permanently deletes the selected data. Back up your database first." msgstr "" -#: includes/admin/database.php:200 -msgid "Schedule" +#: assets/admin/app/tabs/DatabaseTab.jsx:55 +#: assets/admin/app/tabs/DatabaseTab.jsx:110 +msgid "Delete" msgstr "" -#: includes/admin/database.php:202 -msgid "Not scheduled" +#: assets/admin/app/tabs/DatabaseTab.jsx:66 +msgid "Cleanup complete." msgstr "" -#: includes/admin/database.php:203 includes/functions/cron.php:26 -msgid "Daily" +#: assets/admin/app/tabs/DatabaseTab.jsx:68 +msgid "Cleanup failed." msgstr "" -#: includes/admin/database.php:204 includes/functions/cron.php:31 -msgid "Weekly" +#: assets/admin/app/tabs/DatabaseTab.jsx:77 +msgid "Automatic database cleanup" msgstr "" -#: includes/admin/database.php:205 includes/functions/cron.php:36 -msgid "Monthly" +#: assets/admin/app/tabs/DatabaseTab.jsx:78 +msgid "Schedule" msgstr "" -#: includes/admin/database.php:208 +#: assets/admin/app/tabs/DatabaseTab.jsx:85 msgid "Next run" msgstr "" -#: includes/admin/database.php:214 +#: assets/admin/app/tabs/DatabaseTab.jsx:89 msgid "Not set" msgstr "" -#: includes/admin/includes/external_files.php:31 -#: includes/admin/includes/local_files.php:31 -#: includes/functions/miscellaneous.php:261 -msgid "Disable everywhere" +#: assets/admin/app/tabs/DatabaseTab.jsx:110 +#: assets/admin/app/tabs/DatabaseTab.jsx:140 +msgid "Cleaning…" msgstr "" -#: includes/admin/includes/external_files.php:35 -#: includes/admin/includes/local_files.php:35 -#: includes/functions/miscellaneous.php:262 -msgid "Disable only on selected URL" +#: assets/admin/app/tabs/DatabaseTab.jsx:119 +msgid "Enable automatic cleanup" msgstr "" -#: includes/admin/includes/external_files.php:39 -#: includes/admin/includes/local_files.php:39 -#: includes/functions/miscellaneous.php:263 -msgid "Disable everywhere except on selected URL" +#: assets/admin/app/tabs/DatabaseTab.jsx:128 +msgid "Back up your database before running any cleanup. These actions cannot be undone." msgstr "" -#: includes/admin/javascript.php:129 -msgid "JavaScript files not found" +#: assets/admin/app/tabs/DatabaseTab.jsx:141 +msgid "Delete all" msgstr "" -#: includes/admin/javascript.php:142 -msgid "JavaScript settings" +#: assets/admin/app/tabs/HtmlTab.jsx:21 +msgid "Exclude URL(s) from HTML optimization" msgstr "" -#: includes/admin/javascript.php:150 -msgid "Minify inline JavaScript" +#: assets/admin/app/tabs/HtmlTab.jsx:35 +msgid "HTML optimization" msgstr "" -#: includes/admin/javascript.php:157 -msgid "Asynchronously load JavaScript" +#: assets/admin/app/tabs/HtmlTab.jsx:39 +msgid "Enable HTML optimization" msgstr "" -#: includes/admin/javascript.php:161 -msgid "Eliminates render-blocking JavaScript" +#: assets/admin/app/tabs/HtmlTab.jsx:49 +msgid "Normal" msgstr "" -#: includes/admin/javascript.php:167 -msgid "Disable JavaScript optimization for logged-in users" +#: assets/admin/app/tabs/HtmlTab.jsx:58 +msgid "Remove comments" msgstr "" -#: includes/admin/javascript.php:221 -msgid "Exclude URL(s) from JavaScript optimization" +#: assets/admin/app/tabs/HtmlTab.jsx:62 +msgid "Remove HTML comments (conditional comments preserved)" msgstr "" -#: includes/admin/media.php:12 -msgid "Images" +#: assets/admin/app/tabs/HtmlTab.jsx:66 +msgid "Remove type attribute" msgstr "" -#: includes/admin/media.php:16 includes/admin/media.php:192 -msgid "Lazy load" +#: assets/admin/app/tabs/HtmlTab.jsx:70 +msgid "Remove type=\"text/css\" from link tags" msgstr "" -#: includes/admin/media.php:20 -msgid "Lazy load images" +#: assets/admin/app/tabs/HtmlTab.jsx:75 +msgid "Remove type=\"text/javascript\" from script tags" msgstr "" -#: includes/admin/media.php:24 includes/admin/media.php:209 -msgid "Reduces the number of HTTP requests and improves loading time" +#: assets/admin/app/tabs/HtmlTab.jsx:79 +msgid "Remove quotes" msgstr "" -#: includes/admin/media.php:34 -msgid "Disable lazy load on mobile devices" +#: assets/admin/app/tabs/HtmlTab.jsx:83 +msgid "Remove quotes from attributes where possible" msgstr "" -#: includes/admin/media.php:40 -msgid "Responsive images" +#: assets/admin/app/tabs/JsTab.jsx:40 +msgid "JavaScript settings" msgstr "" -#: includes/admin/media.php:44 -msgid "Force images to use srcset attribute" +#: assets/admin/app/tabs/JsTab.jsx:41 +msgid "Minify inline JavaScript" msgstr "" -#: includes/admin/media.php:47 -msgid "" -"Loads the best optimized image depending on users screen size and image " -"sizes settings" +#: assets/admin/app/tabs/JsTab.jsx:44 +msgid "Asynchronous JavaScript" msgstr "" -#: includes/admin/media.php:52 -msgid "Exclude" +#: assets/admin/app/tabs/JsTab.jsx:48 +msgid "Defer JavaScript to remove render-blocking" msgstr "" -#: includes/admin/media.php:55 -msgid "Exclude image by name" +#: assets/admin/app/tabs/JsTab.jsx:52 +msgid "Exclude from defer" msgstr "" -#: includes/admin/media.php:72 -msgid "Add Image" +#: assets/admin/app/tabs/JsTab.jsx:61 +msgid "Delay until interaction" msgstr "" -#: includes/admin/media.php:81 -msgid "" -"Exclude images located in specific html containers like sliders and galleries" +#: assets/admin/app/tabs/JsTab.jsx:65 +msgid "Delay JavaScript until user interaction" msgstr "" -#: includes/admin/media.php:99 includes/admin/media.php:108 -msgid "Enter container id or class name" +#: assets/admin/app/tabs/JsTab.jsx:66 +msgid "Biggest TBT/INP win: scripts run on first scroll, click, or key press. Exclude anything that must run immediately." msgstr "" -#: includes/admin/media.php:100 includes/admin/media.php:108 -msgid "Example" +#: assets/admin/app/tabs/JsTab.jsx:73 +msgid "Exclude from delay" msgstr "" -#: includes/admin/media.php:108 -msgid "Add Container" +#: assets/admin/app/tabs/JsTab.jsx:86 +msgid "Disable JavaScript optimization for logged-in users" msgstr "" -#: includes/admin/media.php:116 -msgid "Exclude URL(s) from image optimization" +#: assets/admin/app/tabs/JsTab.jsx:91 +msgid "Exclude URL(s) from JavaScript optimization" msgstr "" -#: includes/admin/media.php:188 -msgid "Videos" +#: assets/admin/app/tabs/MediaTab.jsx:26 +msgid "Convert images" msgstr "" -#: includes/admin/media.php:204 -msgid "Lazy load videos" +#: assets/admin/app/tabs/MediaTab.jsx:27 +msgid "Convert all images to WebP and AVIF? This can take a while on large media libraries." msgstr "" -#: includes/admin/media.php:218 -msgid "Exclude URL(s)" +#: assets/admin/app/tabs/MediaTab.jsx:28 +msgid "Convert" msgstr "" -#: includes/admin/media.php:303 -msgid "Emoji" +#: assets/admin/app/tabs/MediaTab.jsx:44 +msgid "Images converted." msgstr "" -#: includes/admin/media.php:310 -msgid "Disable Emoji" +#: assets/admin/app/tabs/MediaTab.jsx:46 +msgid "Conversion failed." msgstr "" -#: includes/admin/media.php:314 -msgid "" -"Use default emoji of visitor's browser instead of loading emoji from " -"WordPress.org" +#: assets/admin/app/tabs/MediaTab.jsx:54 +msgid "Emoji & Embeds" msgstr "" -#: includes/admin/media.php:319 -msgid "Embeds" +#: assets/admin/app/tabs/MediaTab.jsx:55 +msgid "Emoji" +msgstr "" + +#: assets/admin/app/tabs/MediaTab.jsx:59 +msgid "Disable WordPress emoji" msgstr "" -#: includes/admin/media.php:326 -msgid "Disable embeds" +#: assets/admin/app/tabs/MediaTab.jsx:62 +msgid "Embeds" msgstr "" -#: includes/admin/media.php:330 -msgid "Prevents embedding content from your site" +#: assets/admin/app/tabs/MediaTab.jsx:66 +msgid "Disable oEmbed discovery" msgstr "" -#: includes/admin/media.php:336 +#: assets/admin/app/tabs/MediaTab.jsx:71 msgid "Image sizes" msgstr "" -#: includes/admin/media.php:343 includes/admin/media.php:354 -msgid "Name" +#: assets/admin/app/tabs/MediaTab.jsx:79 +msgid "Images" msgstr "" -#: includes/admin/media.php:344 includes/admin/media.php:360 -msgid "Width" +#: assets/admin/app/tabs/MediaTab.jsx:80 +#: assets/admin/app/tabs/MediaTab.jsx:172 +msgid "Lazy load" msgstr "" -#: includes/admin/media.php:345 includes/admin/media.php:366 -msgid "Height" +#: assets/admin/app/tabs/MediaTab.jsx:84 +msgid "Lazy load images" msgstr "" -#: includes/admin/media.php:346 includes/admin/media.php:372 -msgid "Crop" +#: assets/admin/app/tabs/MediaTab.jsx:85 +msgid "Defer offscreen images with native loading=\"lazy\"." msgstr "" -#: includes/admin/media.php:347 -msgid "Actions" +#: assets/admin/app/tabs/MediaTab.jsx:92 +msgid "Disable lazy load on mobile devices" msgstr "" -#: includes/admin/media.php:374 includes/functions/miscellaneous.php:259 -msgid "Yes" +#: assets/admin/app/tabs/MediaTab.jsx:97 +msgid "Responsive images" msgstr "" -#: includes/admin/media.php:379 -#, php-format -msgid "Remove image size %s" +#: assets/admin/app/tabs/MediaTab.jsx:101 +msgid "Force srcset on images" msgstr "" -#: includes/admin/media.php:381 -msgid "Remove size" +#: assets/admin/app/tabs/MediaTab.jsx:104 +msgid "Image dimensions" msgstr "" -#: includes/admin/media.php:391 -msgid "Add size" +#: assets/admin/app/tabs/MediaTab.jsx:108 +msgid "Add missing width/height to prevent layout shift (CLS)" msgstr "" -#: includes/admin/media.php:392 -msgid "Restore default image sizes" +#: assets/admin/app/tabs/MediaTab.jsx:112 +msgid "Preload LCP images" msgstr "" -#: includes/admin/media.php:392 -msgid "Restore image sizes" +#: assets/admin/app/tabs/MediaTab.jsx:113 +msgid "Number of above-the-fold images to preload (fetchpriority=high) and skip from lazy load. 0 = off." msgstr "" -#: includes/admin/media.php:398 -msgid "Regenerate thumbnails every time you make some changes to image sizes" +#: assets/admin/app/tabs/MediaTab.jsx:126 +msgid "Next-gen images" msgstr "" -#: includes/admin/media.php:400 -msgid "Regenerate thumbnails" +#: assets/admin/app/tabs/MediaTab.jsx:127 +msgid "Serve WebP/AVIF via when a converted file exists. New uploads convert automatically." msgstr "" -#: includes/admin/metabox.php:13 includes/admin/metabox.php:80 -#: includes/admin/metabox.php:131 includes/admin/metabox.php:183 -#: includes/admin/metabox.php:234 -msgid "Page URL will be added to exclude list" +#: assets/admin/app/tabs/MediaTab.jsx:132 +msgid "Serve WebP/AVIF images" msgstr "" -#: includes/admin/metabox.php:41 includes/admin/metabox.php:68 -msgid "Exclude from cache" +#: assets/admin/app/tabs/MediaTab.jsx:142 +msgid "Converting" msgstr "" -#: includes/admin/metabox.php:46 -msgid "" -"This page is your website home page and it is affected by Exclude URL(s) " -"from cache option. Usually a home page is not excluded from cache. Please " -"check your exclude settings." +#: assets/admin/app/tabs/MediaTab.jsx:143 +msgid "Convert existing images" msgstr "" -#: includes/admin/metabox.php:49 -msgid "This page is affected by URL(s) exclude options on Cache page" +#: assets/admin/app/tabs/MediaTab.jsx:147 +msgid "Exclude by name" msgstr "" -#: includes/admin/metabox.php:63 -msgid "" -"This page is your website home page.
    Do you want to exclude home page " -"from cache?" +#: assets/admin/app/tabs/MediaTab.jsx:151 +msgid "Add image" msgstr "" -#: includes/admin/metabox.php:107 includes/admin/metabox.php:121 -#: includes/admin/metabox.php:158 -msgid "Exclude from CSS optimization" +#: assets/admin/app/tabs/MediaTab.jsx:154 +msgid "Exclude containers" msgstr "" -#: includes/admin/metabox.php:111 -msgid "This page is affected by URL(s) exclude options on CSS page" +#: assets/admin/app/tabs/MediaTab.jsx:154 +msgid "CSS id or class, e.g. #hero or .no-lazy" msgstr "" -#: includes/admin/metabox.php:162 -msgid "This page is affected by URL(s) exclude options on JavaScript page" +#: assets/admin/app/tabs/MediaTab.jsx:158 +msgid "Add container" msgstr "" -#: includes/admin/metabox.php:172 -msgid "Exclude from JS optimization" +#: assets/admin/app/tabs/MediaTab.jsx:161 +#: assets/admin/app/tabs/MediaTab.jsx:179 +msgid "Exclude URL(s)" msgstr "" -#: includes/admin/metabox.php:209 includes/admin/metabox.php:223 -msgid "Exclude from Image optimization" +#: assets/admin/app/tabs/MediaTab.jsx:171 +msgid "Videos" msgstr "" -#: includes/admin/metabox.php:213 includes/admin/metabox.php:264 -msgid "This page is affected by URL(s) exclude options on Media page" +#: assets/admin/app/tabs/MediaTab.jsx:176 +msgid "Lazy load videos & iframes" msgstr "" -#: includes/admin/metabox.php:260 includes/admin/metabox.php:274 -msgid "Exclude from Video lazyload" +#: assets/admin/app/tabs/OverviewTab.jsx:19 +msgid "Safe" msgstr "" -#: includes/admin/settings.php:16 -msgid "Import settings" +#: assets/admin/app/tabs/OverviewTab.jsx:20 +msgid "Page cache, GZIP, browser caching and lazy loading. Works with virtually any theme." msgstr "" -#: includes/admin/settings.php:22 -msgid "Export settings" +#: assets/admin/app/tabs/OverviewTab.jsx:27 +msgid "Balanced" msgstr "" -#: includes/admin/settings.php:25 -msgid "Export" +#: assets/admin/app/tabs/OverviewTab.jsx:29 +msgid "Adds deferred CSS/JS, hosted fonts and modern image formats. Recommended for most sites." msgstr "" -#: includes/admin/settings.php:34 -msgid "Server" +#: assets/admin/app/tabs/OverviewTab.jsx:37 +msgid "Every optimization on, including delayed JavaScript and unused-CSS removal. Test your site after applying." msgstr "" -#: includes/admin/settings.php:39 -msgid "Nginx configuration" +#: assets/admin/app/tabs/OverviewTab.jsx:70 +msgid "Apply preset" msgstr "" -#: includes/admin/settings.php:43 -#, php-format -msgid "" -"%s will work out of the box on Nginx servers, this rewrite rules are not " -"required. However, to optimize your website even more, you should add this " -"rules to your Nginx configuration file." +#: assets/admin/app/tabs/OverviewTab.jsx:71 +msgid "This replaces the settings the preset covers. Your file lists, exclusions and CDN settings are kept." msgstr "" -#: includes/admin/settings.php:45 -msgid "Select all" +#: assets/admin/app/tabs/OverviewTab.jsx:72 +#: assets/admin/app/tabs/OverviewTab.jsx:166 +msgid "Apply" msgstr "" -#: includes/admin/settings.php:52 -msgid "Logs" +#: assets/admin/app/tabs/OverviewTab.jsx:80 +msgid "Preset applied. Reloading…" msgstr "" -#: includes/admin/settings.php:56 -msgid "Troubleshooting logging" +#: assets/admin/app/tabs/OverviewTab.jsx:83 +msgid "Could not apply the preset." msgstr "" -#: includes/admin/settings.php:60 -msgid "Enable troubleshooting logging" +#: assets/admin/app/tabs/OverviewTab.jsx:96 +msgid "Cache status" msgstr "" -#: includes/admin/settings.php:63 -msgid "These logs can be helpful for troubleshooting problems" +#: assets/admin/app/tabs/OverviewTab.jsx:100 +msgid "Active" msgstr "" -#: includes/admin/settings.php:69 -msgid "Log file content" +#: assets/admin/app/tabs/OverviewTab.jsx:101 +msgid "Disabled" msgstr "" -#: includes/admin/settings.php:72 -msgid "Content is auto refreshed every 10 seconds" +#: assets/admin/app/tabs/OverviewTab.jsx:106 +msgid "Cached pages" msgstr "" -#: includes/admin/settings.php:84 -msgid "Clear log file" +#: assets/admin/app/tabs/OverviewTab.jsx:112 +msgid "Cache size" msgstr "" -#: includes/admin/settings.php:93 -msgid "Previous configuration settings" +#: assets/admin/app/tabs/OverviewTab.jsx:119 +msgid "Block fragments" msgstr "" -#: includes/admin/settings.php:114 -msgid "Saved" +#: assets/admin/app/tabs/OverviewTab.jsx:122 +msgid "In Redis" msgstr "" -#: includes/admin/settings.php:117 -msgid "Load configuration settings saved on " +#: assets/admin/app/tabs/OverviewTab.jsx:139 +msgid "Quick setup" msgstr "" -#: includes/admin/settings.php:120 -msgid "Load" +#: assets/admin/app/tabs/OverviewTab.jsx:141 +msgid "Apply a curated configuration in one click, then fine-tune any tab." msgstr "" -#: includes/classes/api.php:130 -#, php-format -msgid "Call to undefined method %s" +#: assets/admin/app/tabs/OverviewTab.jsx:153 +msgid "Recommended" msgstr "" -#: includes/classes/cli.php:23 -msgid "Flushing the cache..." +#: assets/admin/app/tabs/OverviewTab.jsx:165 +msgid "Applying…" msgstr "" -#: includes/classes/cli.php:25 -msgid "Cache flushed." +#: assets/admin/app/tabs/OverviewTab.jsx:173 +msgid "Active optimizations" msgstr "" -#: includes/classes/cli.php:73 -msgid "Running tranisent cleanup" +#: assets/admin/app/tabs/OverviewTab.jsx:189 +msgid "Health checks" msgstr "" -#: includes/classes/cli.php:75 -msgid "Transient cleanup complete" +#: assets/admin/app/tabs/Placeholder.jsx:8 +msgid "is being rebuilt in the next step." msgstr "" -#: includes/classes/cli.php:81 -msgid "Running revisions cleanup" +#: assets/admin/app/tabs/SettingsTab.jsx:26 +msgid "Prefetch" msgstr "" -#: includes/classes/cli.php:83 -msgid "Revisions cleanup complete" +#: assets/admin/app/tabs/SettingsTab.jsx:61 +msgid "Log cleared." msgstr "" -#: includes/classes/cli.php:89 -msgid "Running drafts cleanup" +#: assets/admin/app/tabs/SettingsTab.jsx:63 +msgid "Could not clear the log." msgstr "" -#: includes/classes/cli.php:91 -msgid "Drafts cleanup complete" +#: assets/admin/app/tabs/SettingsTab.jsx:69 +msgid "Restore settings" msgstr "" -#: includes/classes/cli.php:97 -msgid "Running trash cleanup" +#: assets/admin/app/tabs/SettingsTab.jsx:70 +msgid "Your current settings will be replaced by this saved configuration." msgstr "" -#: includes/classes/cli.php:99 -msgid "Trash cleanup complete" +#: assets/admin/app/tabs/SettingsTab.jsx:79 +msgid "Settings restored. Reloading…" msgstr "" -#: includes/classes/cli.php:105 -msgid "Running spam cleanup" +#: assets/admin/app/tabs/SettingsTab.jsx:82 +msgid "Could not restore settings." msgstr "" -#: includes/classes/cli.php:107 -msgid "Spam cleanup complete" +#: assets/admin/app/tabs/SettingsTab.jsx:100 +msgid "Export failed." msgstr "" -#: includes/classes/cli.php:113 -msgid "Running cron tasks cleanup" +#: assets/admin/app/tabs/SettingsTab.jsx:112 +msgid "Settings imported. Reloading…" msgstr "" -#: includes/classes/cli.php:115 -msgid "Cron tasks cleanup complete" +#: assets/admin/app/tabs/SettingsTab.jsx:115 +msgid "Import failed - invalid file." msgstr "" -#: includes/classes/cli.php:126 -msgid "Running database cleanup" +#: assets/admin/app/tabs/SettingsTab.jsx:125 +msgid "Restore points" msgstr "" -#: includes/classes/cli.php:128 -msgid "Database cleanup complete" +#: assets/admin/app/tabs/SettingsTab.jsx:128 +msgid "The last five saved configurations appear here so you can roll back a change." msgstr "" -#: includes/classes/parser.php:94 -msgid "error" +#. translators: %s: settings group name. +#: assets/admin/app/tabs/SettingsTab.jsx:143 +#, js-format +msgid "%s settings" msgstr "" -#: includes/classes/parser.php:95 includes/classes/parser.php:98 -msgid "both head and body tag should be present in template file" +#: assets/admin/app/tabs/SettingsTab.jsx:157 +msgid "Restoring…" msgstr "" -#: includes/classes/parser.php:932 -msgid "Optimized by" +#: assets/admin/app/tabs/SettingsTab.jsx:166 +msgid "About" msgstr "" -#: includes/classes/parser.php:956 -#, php-format -msgid "Cache file was created in %s seconds on %s at %s" +#: assets/admin/app/tabs/SettingsTab.jsx:168 +msgid "Export your configuration to move it between sites, or import a saved configuration file." msgstr "" -#: includes/functions/admin.php:270 -msgid "Temporarily disable" +#: assets/admin/app/tabs/SettingsTab.jsx:179 +msgid "Import / Export" msgstr "" -#: includes/functions/backend.php:52 -#, php-format -msgid "" -"File advanced-cache.php is missing. If you updated your " -"installation of %s recently, try to deactivate and then activate the plugin " -"again." +#: assets/admin/app/tabs/SettingsTab.jsx:180 +msgid "Export settings" msgstr "" -#: includes/functions/backend.php:237 -msgid "is temporarily disabled" +#: assets/admin/app/tabs/SettingsTab.jsx:182 +msgid "Download settings file" msgstr "" -#: includes/functions/backend.php:250 -#, php-format -msgid "" -"%s: Log file is getting large, either clear the log or disable " -"troubleshooting logging" +#: assets/admin/app/tabs/SettingsTab.jsx:185 +msgid "Import settings" msgstr "" -#: includes/functions/backend.php:262 -#, php-format -msgid "%s: missing writing permissions for file .htaccess" +#: assets/admin/app/tabs/SettingsTab.jsx:196 +msgid "Nginx rules" msgstr "" -#: includes/functions/backend.php:275 -#, php-format -msgid "%s: enter Cloudflare credentials" +#: assets/admin/app/tabs/SettingsTab.jsx:198 +msgid "Add these rules to your nginx server block, then reload nginx." msgstr "" -#: includes/functions/cron.php:41 -msgid "Every minute" +#: assets/admin/app/tabs/SettingsTab.jsx:204 +msgid "Server" msgstr "" -#: includes/functions/cron.php:46 -msgid "Every 5 minutes" +#: assets/admin/app/tabs/SettingsTab.jsx:206 +msgid "Browser cache and gzip rules are written to .htaccess automatically." msgstr "" -#: includes/functions/db.php:85 -msgid "You are doing it wrong" +#: assets/admin/app/tabs/SettingsTab.jsx:213 +msgid "Redis object cache" msgstr "" -#: includes/functions/files.php:350 -msgid "Log file cleared" +#: assets/admin/app/tabs/SettingsTab.jsx:217 +msgid "Enable persistent object cache" msgstr "" -#: includes/functions/image.php:68 -msgid "Size name already in use" +#: assets/admin/app/tabs/SettingsTab.jsx:218 +msgid "Stores WordPress query and option lookups in Redis to cut database load. Installs an object-cache.php drop-in." msgstr "" -#: includes/functions/image.php:190 -#, php-format -msgid "%s image left" -msgid_plural "%s images left" -msgstr[0] "" -msgstr[1] "" +#: assets/admin/app/tabs/SettingsTab.jsx:226 +msgid "No supported object cache backend was detected. Install and enable the Redis PHP extension to use a persistent object cache." +msgstr "" -#: includes/functions/image.php:202 -msgid "Done" +#: assets/admin/app/tabs/SettingsTab.jsx:234 +msgid "Troubleshooting" msgstr "" -#: includes/functions/miscellaneous.php:257 -msgid "Are you sure?" +#: assets/admin/app/tabs/SettingsTab.jsx:235 +msgid "Logging" msgstr "" -#: includes/functions/miscellaneous.php:264 -msgid "Something went wrong" +#: assets/admin/app/tabs/SettingsTab.jsx:239 +msgid "Enable troubleshooting log" msgstr "" -#: includes/functions/miscellaneous.php:265 -msgid "Regenerating thumbs" +#: assets/admin/app/tabs/SettingsTab.jsx:240 +msgid "Records cache and optimization activity to help diagnose issues." msgstr "" -#: includes/functions/miscellaneous.php:266 -msgid "Regenerate thumbnails may take a long time. Do not close your browser." +#: assets/admin/app/tabs/SettingsTab.jsx:245 +msgid "Log file" msgstr "" -#: includes/functions/plugin.php:220 -msgid "The following plugins are not compatible with" +#: assets/admin/app/tabs/SettingsTab.jsx:250 +msgid "The log is empty." msgstr "" -#: includes/functions/plugin.php:227 -msgid "Deactivate" +#: assets/admin/app/tabs/SettingsTab.jsx:254 +msgid "Content refreshes automatically every 10 seconds." msgstr "" -#: includes/functions/settings.php:57 -msgid "Invalid settings file" +#: assets/admin/app/tabs/SettingsTab.jsx:257 +msgid "Clear log" msgstr "" -#: includes/functions/settings.php:269 -msgid "Settings saved" +#: assets/blocks/cache/index.js:9 +msgid "Saves everything inside this block so it loads faster." msgstr "" -#: includes/functions/settings.php:330 -msgid "Settings file loaded" +#: assets/blocks/cache/index.js:12 +msgid "cache" msgstr "" -#: includes/functions/settings.php:520 -msgid "Files list cleared" +#: assets/blocks/cache/index.js:12 +msgid "fragment" msgstr "" -#. Plugin Name of the plugin/theme -msgid "WP Performance" +#: assets/blocks/cache/index.js:12 +msgid "performance" +msgstr "" + +#: assets/blocks/cache/index.js:28 +msgid "Caching" msgstr "" -#. Plugin URI of the plugin/theme -msgid "https://www.wp-performance.com" +#: assets/blocks/cache/index.js:31 +msgid "Cache for (seconds)" msgstr "" -#. Description of the plugin/theme -msgid "WP Performance Optimizer" +#: assets/blocks/cache/index.js:32 +msgid "Leave 0 to use the default." msgstr "" -#. Author of the plugin/theme -msgid "Ante Laca" +#: assets/blocks/cache/index.js:38 +msgid "Cache each page separately" +msgstr "" + +#: assets/blocks/cache/index.js:39 +msgid "Turn off to reuse one copy everywhere, like a menu or footer." +msgstr "" + +#: assets/blocks/cache/index.js:44 +msgid "Separate copy for logged-in visitors" +msgstr "" + +#: assets/blocks/cache/index.js:49 +msgid "Separate copy for each user role" msgstr "" -#. Author URI of the plugin/theme -msgid "https://www.antelaca.xyz" +#: assets/blocks/cache/index.js:54 +msgid "Separate copy on mobile" msgstr "" diff --git a/object-cache.php b/object-cache.php new file mode 100644 index 0000000..bf064b3 --- /dev/null +++ b/object-cache.php @@ -0,0 +1,361 @@ +add($key, $data, $group, (int) $expire); +} + +function wp_cache_add_multiple(array $data, $group = '', $expire = 0) +{ + $result = []; + foreach ($data as $key => $value) { + $result[$key] = wp_cache_add($key, $value, $group, $expire); + } + return $result; +} + +function wp_cache_replace($key, $data, $group = '', $expire = 0) +{ + return $GLOBALS['wp_object_cache']->replace($key, $data, $group, (int) $expire); +} + +function wp_cache_set($key, $data, $group = '', $expire = 0) +{ + return $GLOBALS['wp_object_cache']->set($key, $data, $group, (int) $expire); +} + +function wp_cache_set_multiple(array $data, $group = '', $expire = 0) +{ + $result = []; + foreach ($data as $key => $value) { + $result[$key] = wp_cache_set($key, $value, $group, $expire); + } + return $result; +} + +function wp_cache_get($key, $group = '', $force = false, &$found = null) +{ + return $GLOBALS['wp_object_cache']->get($key, $group, $force, $found); +} + +function wp_cache_get_multiple($keys, $group = '', $force = false) +{ + return $GLOBALS['wp_object_cache']->get_multiple($keys, $group, $force); +} + +function wp_cache_delete($key, $group = '') +{ + return $GLOBALS['wp_object_cache']->delete($key, $group); +} + +function wp_cache_delete_multiple(array $keys, $group = '') +{ + $result = []; + foreach ($keys as $key) { + $result[$key] = wp_cache_delete($key, $group); + } + return $result; +} + +function wp_cache_incr($key, $offset = 1, $group = '') +{ + return $GLOBALS['wp_object_cache']->incr($key, (int) $offset, $group); +} + +function wp_cache_decr($key, $offset = 1, $group = '') +{ + return $GLOBALS['wp_object_cache']->decr($key, (int) $offset, $group); +} + +function wp_cache_flush() +{ + return $GLOBALS['wp_object_cache']->flush(); +} + +function wp_cache_flush_runtime() +{ + return $GLOBALS['wp_object_cache']->flush_runtime(); +} + +function wp_cache_supports($feature) +{ + return in_array($feature, ['get_multiple', 'set_multiple', 'add_multiple', 'delete_multiple', 'flush_runtime'], true); +} + +function wp_cache_close() +{ + return true; +} + +function wp_cache_add_global_groups($groups) +{ + $GLOBALS['wp_object_cache']->add_global_groups($groups); +} + +function wp_cache_add_non_persistent_groups($groups) +{ + $GLOBALS['wp_object_cache']->add_non_persistent_groups($groups); +} + +function wp_cache_switch_to_blog($blog_id) +{ + $GLOBALS['wp_object_cache']->switch_to_blog((int) $blog_id); +} + +function wp_cache_reset() +{ +} + +class WPP_Object_Cache +{ + /** @var array */ + private array $cache = []; + private ?\Redis $redis = null; + private bool $connected = false; + /** @var array */ + private array $globalGroups = []; + /** @var array */ + private array $nonPersistent = ['counts' => true, 'plugins' => true]; + private int $blogPrefix = 1; + private string $salt; + + public int $cache_hits = 0; + public int $cache_misses = 0; + + public function __construct() + { + $this->salt = defined('WP_CACHE_KEY_SALT') ? (string) WP_CACHE_KEY_SALT : ''; + + // Without a site-specific default, two installs sharing one Redis would + // collide on identical keys and read each other's options and users. + if ($this->salt === '') { + $this->salt = substr(md5( + (defined('DB_NAME') ? (string) DB_NAME : '') + . '|' . (string) ($GLOBALS['table_prefix'] ?? '') + . '|' . (defined('ABSPATH') ? (string) ABSPATH : '') + ), 0, 12); + } + if (function_exists('get_current_blog_id')) { + $this->blogPrefix = (int) get_current_blog_id(); + } + + if (class_exists('Redis')) { + try { + $this->redis = new \Redis(); + $host = defined('WP_REDIS_HOST') ? WP_REDIS_HOST : '127.0.0.1'; + $port = defined('WP_REDIS_PORT') ? (int) WP_REDIS_PORT : 6379; + $this->connected = (bool) @$this->redis->connect($host, $port, 1.0); + if ($this->connected && defined('WP_REDIS_PASSWORD') && WP_REDIS_PASSWORD) { + @$this->redis->auth(WP_REDIS_PASSWORD); + } + if ($this->connected && defined('WP_REDIS_DATABASE')) { + @$this->redis->select((int) WP_REDIS_DATABASE); + } + } catch (\Throwable $e) { + $this->connected = false; + } + } + } + + public function add_global_groups($groups): void + { + foreach ((array) $groups as $group) { + $this->globalGroups[$group] = true; + } + } + + public function add_non_persistent_groups($groups): void + { + foreach ((array) $groups as $group) { + $this->nonPersistent[$group] = true; + } + } + + public function switch_to_blog($blogId): void + { + $this->blogPrefix = (int) $blogId; + } + + public function get($key, $group = 'default', $force = false, &$found = null) + { + $group = $group ?: 'default'; + $id = $this->id($key, $group); + + if (! $force && array_key_exists($id, $this->cache)) { + $found = true; + $this->cache_hits++; + return is_object($this->cache[$id]) ? clone $this->cache[$id] : $this->cache[$id]; + } + + if ($this->persistent($group)) { + $value = $this->call(static fn ($redis) => $redis->get($id), false); + if ($value !== false) { + $value = maybe_unserialize($value); + $this->cache[$id] = $value; + $found = true; + $this->cache_hits++; + return is_object($value) ? clone $value : $value; + } + } + + $found = false; + $this->cache_misses++; + return false; + } + + public function get_multiple($keys, $group = 'default', $force = false): array + { + $result = []; + foreach ((array) $keys as $key) { + $found = null; + $result[$key] = $this->get($key, $group, $force, $found); + } + return $result; + } + + public function set($key, $data, $group = 'default', $expire = 0): bool + { + $group = $group ?: 'default'; + $id = $this->id($key, $group); + + $this->cache[$id] = is_object($data) ? clone $data : $data; + + if ($this->persistent($group)) { + $serialized = maybe_serialize($data); + $this->call(static fn ($redis) => $expire > 0 + ? $redis->setex($id, (int) $expire, $serialized) + : $redis->set($id, $serialized)); + } + return true; + } + + public function add($key, $data, $group = 'default', $expire = 0): bool + { + $group = $group ?: 'default'; + $id = $this->id($key, $group); + if (array_key_exists($id, $this->cache)) { + return false; + } + if ($this->persistent($group) && $this->call(static fn ($redis) => $redis->exists($id), false)) { + return false; + } + return $this->set($key, $data, $group, $expire); + } + + public function replace($key, $data, $group = 'default', $expire = 0): bool + { + $found = null; + $this->get($key, $group, false, $found); + return $found ? $this->set($key, $data, $group, $expire) : false; + } + + public function delete($key, $group = 'default'): bool + { + $group = $group ?: 'default'; + $id = $this->id($key, $group); + unset($this->cache[$id]); + if ($this->persistent($group)) { + $this->call(static fn ($redis) => $redis->del($id)); + } + return true; + } + + public function incr($key, $offset = 1, $group = 'default') + { + $found = null; + $value = $this->get($key, $group, false, $found); + if (! $found) { + return false; + } + $value = max(0, (int) $value + (int) $offset); + $this->set($key, $value, $group); + return $value; + } + + public function decr($key, $offset = 1, $group = 'default') + { + return $this->incr($key, -(int) $offset, $group); + } + + /** + * Deletes only this install's keys. flushDb() would empty the whole Redis + * database, which is shared by default with anything else on the server. + */ + public function flush(): bool + { + $this->cache = []; + if (! $this->connected) { + return true; + } + + $pattern = "wpp:{$this->salt}:*"; + + return $this->call(static function ($redis) use ($pattern) { + $redis->setOption(\Redis::OPT_SCAN, \Redis::SCAN_RETRY); + $cursor = null; + while (($keys = $redis->scan($cursor, $pattern, 500)) !== false) { + if ($keys === []) { + continue; + } + method_exists($redis, 'unlink') ? $redis->unlink($keys) : $redis->del($keys); + } + return true; + }) === true; + } + + public function flush_runtime(): bool + { + $this->cache = []; + return true; + } + + private function persistent(string $group): bool + { + return $this->connected && ! isset($this->nonPersistent[$group]); + } + + /** + * Run a Redis command, degrading to the in-memory cache on any failure. + * + * phpredis throws RedisException not only when the connection drops but for + * server replies such as NOAUTH, LOADING, MISCONF and OOM. Uncaught, that is + * a fatal error on every front-end and admin request, which cannot then be + * switched off from the admin. Dropping the connection keeps the request + * alive on the runtime array cache instead. + */ + private function call(callable $command, mixed $fallback = false): mixed + { + if (! $this->connected) { + return $fallback; + } + + try { + return $command($this->redis); + } catch (\Throwable $e) { + $this->connected = false; + return $fallback; + } + } + + private function id($key, string $group): string + { + $prefix = isset($this->globalGroups[$group]) ? 'global' : (string) $this->blogPrefix; + return "wpp:{$this->salt}:{$prefix}:{$group}:{$key}"; + } +} diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..6adf046 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,20423 @@ +{ + "name": "wp-performance", + "version": "2.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "wp-performance", + "version": "2.0.0", + "dependencies": { + "@wordpress/api-fetch": "^7.0.0", + "@wordpress/element": "^6.0.0", + "@wordpress/i18n": "^5.0.0", + "@wordpress/url": "^4.0.0", + "lucide-react": "^1.16.0" + }, + "devDependencies": { + "@wordpress/scripts": "^30.0.0" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.7.tgz", + "integrity": "sha512-yJ474Zv3cwiSOO9nXJuqzvwEeM+chDuQ8GJirw+pZ91sCGCyOZ3dJkVE09fTV0VEVzXyLWhh3G/AolYTPX7Mow==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.25.7", + "@babel/generator": "^7.25.7", + "@babel/helper-compilation-targets": "^7.25.7", + "@babel/helper-module-transforms": "^7.25.7", + "@babel/helpers": "^7.25.7", + "@babel/parser": "^7.25.7", + "@babel/template": "^7.25.7", + "@babel/traverse": "^7.25.7", + "@babel/types": "^7.25.7", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/eslint-parser": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.25.7.tgz", + "integrity": "sha512-B+BO9x86VYsQHimucBAL1fxTJKF4wyKY6ZVzee9QgzdZOUfs3BaR6AQrgoGrRI+7IFS1wUz/VyQ+SoBcSpdPbw==", + "dev": true, + "dependencies": { + "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", + "eslint-visitor-keys": "^2.1.0", + "semver": "^6.3.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || >=14.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.11.0", + "eslint": "^7.5.0 || ^8.0.0 || ^9.0.0" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz", + "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.29.7.tgz", + "integrity": "sha512-OoK6239jHPuSQOoS0kfTVKn0b/rVTk0seKq4Gd2UMLtmOVLjDC0ki3e+c90Trqv2gMfvJFqkiljrr568+qddiw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.29.7.tgz", + "integrity": "sha512-IY3ZD9Tmooqr3TUhc3DUWxiuo8xx1DWLhd5M7hQ+ZWJamqM2BbalrBJb2MisSLoYorOj75U03qULCxQTY9r3hg==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-member-expression-to-functions": "^7.29.7", + "@babel/helper-optimise-call-expression": "^7.29.7", + "@babel/helper-replace-supers": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7", + "@babel/traverse": "^7.29.7", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.29.7.tgz", + "integrity": "sha512-907Uymvqgg1dwUA+7IGwFAOSYzQOuzPXKNJ1yxzwPffzkYFg2q2eHi1fIOs6sXkG9NbIUMunnUlkYsfRFNvomg==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "regexpu-core": "^6.3.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.8.tgz", + "integrity": "sha512-47UwBLPpQi1NoWzLuHNjRoHlYXMwIJoBf7MFou6viC/sIHWYygpvr0B6IAyh5sBdA2nr2LPIRww8lfaUVQINBA==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "debug": "^4.4.3", + "lodash.debounce": "^4.0.8", + "resolve": "^1.22.11" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.29.7.tgz", + "integrity": "sha512-j+7JYmk1JYDtACIGj0QJqqWZjoUpMoEikQGADMaHgCMCSDqd2+P32rfcibUNrGOMWrlzK1WJBdxrB3JJQZwWtg==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.29.7.tgz", + "integrity": "sha512-+kmGVjcT9RGYzoDwdwEqEvGgKe3BYq+O1iGzjFubaNgZHwYHP6lsF2Yghf4kEuv9BV7tYDZ913aBW9am6YKong==", + "dev": true, + "dependencies": { + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz", + "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.29.7.tgz", + "integrity": "sha512-16AMiW26DbXWBbr3B8wNozKM0ydMLB892vaOaJW/fPJdnT8vJk5sdkQcU/isqUxyCE0cEoa8wZOcbgDuC4b6Og==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-wrap-function": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.29.7.tgz", + "integrity": "sha512-atfGXWSeCiF4DnKZIfmJfQRkSw9b9gNNXR1kqKjbhG4pGYCOnkp8OcTB8E3NXjBu8NpheSnOeNKz8KT7UNFTmQ==", + "dev": true, + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.29.7", + "@babel/helper-optimise-call-expression": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.29.7.tgz", + "integrity": "sha512-brcMGQaVzIeUb+6/bs1Av0f8YuNNjKY2JyvfRCsFuFsdKccEQ5Ges2y74D74NZ1Rz8lKJ9ksJkfqwQFJ/iNEyQ==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.29.7.tgz", + "integrity": "sha512-iES0Skag9ERIF68aXadpO6dbXa03mNWK3sEqJaMnLNs/eC3l0lkImdfoy6Y09/SfkpawdAB4RjQ7PVA7TcVGdw==", + "dev": true, + "dependencies": { + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", + "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", + "dev": true, + "dependencies": { + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", + "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.29.7" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.29.7.tgz", + "integrity": "sha512-j8SrR0zLZrRsC09DlszEx8FpMiwukKffYXMK0d5LmOglO7vGG6sz/BR/20yHqWH+Lnn31JTt2PE3hIWNgM2J6w==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.29.7.tgz", + "integrity": "sha512-r8j8escF+U2FUHo0KOhPUdMzUO+jp9fInva6+ACVAF3Y97Ev+5iNZwiqTghmzNeWwDkOPlYuTcfb1vDaoZKmAQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.29.7.tgz", + "integrity": "sha512-GE1TFSiuFeGsCxmYXZl8HwoPrVlwe4rHPFE8weieGKZqnDORK+Ar3vgWMgW+AOxQ6/2TgLSKx9p6W7O4rC6qgQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-rest-destructuring-rhs-array": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-rest-destructuring-rhs-array/-/plugin-bugfix-safari-rest-destructuring-rhs-array-7.29.7.tgz", + "integrity": "sha512-oBNVCvnO5tND+xSopWvV8WNGfpTfgP4Zr/YXXSj8zfmcPktp5Ku/aZlsIowgSD4fjmgHn6sGmB9APVsU5zOdhA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.29.7.tgz", + "integrity": "sha512-QQt9qKHZ2sg/kivaLr7lnQr8HVrQDdBNSfCsTjiDxRuX/K5ORyKq+Bu8Xr0cDE3Dfkv0cw28Ve0EKyKMvulkOw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7", + "@babel/plugin-transform-optional-chaining": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.29.7.tgz", + "integrity": "sha512-pn6QacGLgvCcwc+syUhKE/qSjV2D1IHDB84RNxWYSt1mW3K/SCtjinZ2p0cETJxAWBjPy3K/1lHwG5BjjPxNlw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "dev": true, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.29.7.tgz", + "integrity": "sha512-/An1OCBN93thpBAGyfsK2pcf0jvju1SAtKkL2Ny++B5Sy6sqgzXDQH1cZxWbF96Wuk+bn41MDA9bLd4VVAw6rw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.29.7.tgz", + "integrity": "sha512-zGYcYfq/WmZ4V+kBIXQon9dSSc8ircGZqw9ZaNhhGj9nZkeBu1jHLBDQqYYi5WA9uawvA2sIMbry2nCFhf5Djg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.29.7.tgz", + "integrity": "sha512-TSu8+mHCoEaaCDEZ0I3+6mvTBYR4PCxQwf2z9/r5Tbztv6NaLR3B9thGTTxX2WGuGHJqRiAbKPeGTJ5XWXVg6A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.29.7.tgz", + "integrity": "sha512-ngr+82Sh0xMz25TPCZi+nC2iTzjfCdWS2ONXTp/PtSCHCgaCNBpdMqgvJ2ccdLlClVZ7sisIgB914j/JFe+RZA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.29.7.tgz", + "integrity": "sha512-N7zArUXWzAMzm+/N0uPBeVB3Fam5lMxtUwMmDK5f/IBBS7a7p1qeUoxd/6CckXoxUdgsntq1Dh8xNW06maZbDQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.29.7.tgz", + "integrity": "sha512-d98gXZkgswvkyohMBABkhm3GeXhYj8psWfwQ2C7gtfrKGTykQa/iOIi+JJhwMjPlZ6Vm2XN+DCf3Es1EoG4ZLA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-remap-async-to-generator": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.29.7.tgz", + "integrity": "sha512-pcUb2SS+RMo9TWVBwKGI5ShtoG7R+zBsFmCKDa6fe8c+hPr3XJlZgoE5j6i8W7gDjhyvy+85vmYexanvXh3d1w==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-remap-async-to-generator": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.29.7.tgz", + "integrity": "sha512-cUSmjh72N+rN4PrkFlN1dJwNCwjVp5d38/CQrEsFggkD10UiFlBFgdH3tv5dNsLuHY+3S8db2xCHjhZcv5WgvA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.29.7.tgz", + "integrity": "sha512-ONyr4+AZhKh8yKWInVxU9AXA9EbsyeLcL6V0dJy6M2/62vuvpGm29zzuymbTpdc451GEpDIdAyPLP3r+P61yKQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.29.7.tgz", + "integrity": "sha512-GtcpjFvanPfzNQi3eTitsCqtRRmmqzpy/A+yhTR1HaZo1Ly3EA8ZXxlPyHdR8/IuRMYc3E4wdGBewB2QKQjAaA==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.29.7.tgz", + "integrity": "sha512-kibJgmEdX2iMwsHY2tSZNDgj8PwIlCQz7FK9KuGKO8zsuoUwSEhoNnNVp/emKWrbY4HeO6kkXfdMqRKKKXBm2A==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.29.7.tgz", + "integrity": "sha512-qV0OGGBVacduzQHE649JyCneOFI/maT+YKsO+K4Yi3xv2wTPNjM/W2o2gdzMwEAZz7fXNTHAe0NcSg30bIN69g==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-globals": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-replace-supers": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.29.7.tgz", + "integrity": "sha512-RK7/IyU5phpuCdBAuig5VkzG/EnbDaui5SQGdU9BFrHdV+mV4cUjLMQ9lJDjLNtWHsqtiefpGZUXQP2BiTYMsA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/template": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.29.7.tgz", + "integrity": "sha512-iPX8aD6H9zV5s7ZsqTdNocPN/MGQ5sSMnElKrktxjJRMnB2jN/1p2+R7GkfD6CAYoVFqy5A4XnSIUeGgJzIWpg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.29.7.tgz", + "integrity": "sha512-3qc18hsD2RdZiyJNDNc7HQpv6xbncwh8FYtxNFFzclSyh/trPD9KkVR9BDECUjDLvb7yJVF15GfYUuC+LMkkiQ==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.29.7.tgz", + "integrity": "sha512-6IvRRriEMqnBwD6chtxdLpMYCHWEzN+oL5cyQtjykya19UgzbmKhxmhZgKC/LHxS2nYr9Q/qYPZ5Lr6jOL9+yQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.29.7.tgz", + "integrity": "sha512-2wiIyo2BjtgU7HufSeDnL9L2O7zr8jmhFKuSr65VpRkUiRKRNpb0mdlk56+XPPKoIrfHqzbMuglDvZun0RISsA==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.29.7.tgz", + "integrity": "sha512-giOlEm/EFjfjr+te9NsdjkUo2v4f8rS/SXPumRVHAtbNcyNlvtREkU1dZzaIDclNpnaVhlCqRdFKhJBjBikzLg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-explicit-resource-management": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-explicit-resource-management/-/plugin-transform-explicit-resource-management-7.29.7.tgz", + "integrity": "sha512-Rstj7coNz8sE+7Ju7ihpHLI564lsK5pUpNNlvptCIC/16E/S5hbl6n3kESPKdNRmqEWlpn5xpS5Q2dvXBsySLw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/plugin-transform-destructuring": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.29.7.tgz", + "integrity": "sha512-zFpMOTLZBdW5LfObqcSbL6kefg4R4eLdmvS0wbN9M6D5Mym/sKm9toOoWyVOa+xDjvCnuWcHls2YonXwHvH3CQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.29.7.tgz", + "integrity": "sha512-24B2nOy2TeJSMheqwPD4DDQOV/elLSIlKxjZt4i05H5AgdPdWR3n18HnNrcJ+j76WJd9gbwb9jPjNYUy6RautA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.29.7.tgz", + "integrity": "sha512-zeSIHh0+E1Um1WJRXCFlHQYu2ieJNdivLLjlBEp+dIBu3S51n+SZZmIXjxnItw6pz56Cn+KvK68BIBVsxq2JiQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.29.7.tgz", + "integrity": "sha512-otRWaHXE6fbAGkePvaj/kvs3HsqXfPhlnzwSOlnFgbqCPMd975dW+4wZ00WFBt+/YlBGcJwNrARQTOJOb4ZrIg==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.29.7.tgz", + "integrity": "sha512-RRnE2+eon1rJAq8MnoF1b5kTpY1vU88twHcvcKMrsqP/jxIRqDVs9iJB5fqPuqyeFAW0wJo4MlUIPpQCq/aRsg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.29.7.tgz", + "integrity": "sha512-DZ/oLP21ZuWx1vKqnoNv6/tvEK48AQOBRai40CX9dTjGluvT/YZCyY3rryDtyUqCEoyNroy5KKPwX2iQCiRvyw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.29.7.tgz", + "integrity": "sha512-A0H91hh6W8MFRkp5TqJmMr39jzGD1A1E1Ysiv2O06Sfbhkapm+XyIzxWCEh5kqwOZ1/8QZ0dY3SeQ7XBqfJd5Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.29.7.tgz", + "integrity": "sha512-hl1kwFZCCiDyfH25Xmco9jTrkPgnS9pmOzSG7W5I4SaGbLeqKv417hcU2RKmaxoPEgsoJh7ZPOrnPGq99bHoUg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.29.7.tgz", + "integrity": "sha512-fxtQoH3m5ywUSIfaH0FGCzWu4McsYon5bD3K4XnskC7f+OyQMj7rsOMi4NvvmJ83WwBAg4UCe+ov4VZlqEvyew==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.29.7.tgz", + "integrity": "sha512-j0vCldybPC5b5dwCQOJ21uKtHzt7hxLygJTg9eF1ScfaikEDNfzn94XoW5Fi+seBR0nCyL23xaBFFkq7dTM8XQ==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.29.7.tgz", + "integrity": "sha512-TM2ZcQLoG2/y4HODiStCo10DibYhWhGWAwVv+EQKmG/7GFl0N+AAmUiXOMKM+aiJ9XBJ9AHVZBvTzMnJ2sM3cQ==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.29.7.tgz", + "integrity": "sha512-B4UkaTK3QpgCwJnrxKfMPKdo92CN7OKXAlpAAnM3UPu0Q0lCCk57ylA9AJbRy2v8dDKOPAAWcoR6CMyeoHwRCA==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.29.7.tgz", + "integrity": "sha512-vuFoLwr4qnv2xbZ16SQd6uPcH5FNrLHhk/Jzo++0XJFcaDsr4gjJVg6j398oMHiC+83k/GiBzviwF5KBJkPUtQ==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.29.7.tgz", + "integrity": "sha512-fEo41GmsOUhOBlw8ioo6zvjX5Xc2Lqkzlyfqbpsk3eB6TReV18uhxZ0esfEokVbY2+PVJAQHNKxER6lGrzNd3A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.29.7.tgz", + "integrity": "sha512-idmp1dFaekP9GbcMvG24Kvw2BfhFZjHnNJCkV4WuIY4PskJzwI3f1N5OdgYke38T7rftO6ERulFRn2cFeZwRkg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.29.7.tgz", + "integrity": "sha512-zR7fv/z14OjgHl4AgRtkDBvBMhIzCxqV/qN/2BCRC7LjFwvuzjYe7gDWxC4Wl/SNsLM6SE1IWvRPYMgSJaUvNw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.29.7.tgz", + "integrity": "sha512-Ld98jn4c0smUywL57m7SgsHq3OpThOa6LqZJif3G6jYOovPleoFhVrBJ1WegRApSFB2wu4+RelAj9AC9G08Z4A==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/plugin-transform-destructuring": "^7.29.7", + "@babel/plugin-transform-parameters": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.29.7.tgz", + "integrity": "sha512-Ea/diGcw0twB5IlZPO5sgET6fJsLJqPABqTuFWIR+iMPGPZJkATEIWx0wa+aEQ5UY1CBQyP/gkAiLEqn1vBiQA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-replace-supers": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.29.7.tgz", + "integrity": "sha512-sLsyndxK2VwX6yNUOakMb7Sh553ZTe/vVM1XJ+9Z5aW1ytsc8xOIwmyk05NNjN60vkc5/KqoTH6hB4V41LJhng==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.29.7.tgz", + "integrity": "sha512-6GM1dhvK3gNODkXcEcMCOLEDCLSoZ/sBbro2Ax8HURyasQ4NshagQixkRFdh5niI6E4gmA/jYI/4aT7rRos3ZQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.29.7.tgz", + "integrity": "sha512-ZDOBqV/qLYJI0YElr8DcENEyARsFQeESqWXH6gZlghYXuPPjvweuDhP4VyEi4BlUBlLRFZVjxoZDMjxhLW766g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.29.7.tgz", + "integrity": "sha512-/6Rz4DK1ETDEM/bWHsPHcaEe7ZaT1EqSXjtSP/L0DijOYuaUhiRiOKcwpZ8P7zR4xXEHc2ITdiCgBm9Tpyv9ug==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.29.7.tgz", + "integrity": "sha512-+BNo06dnrzdNNqCm1X6YUaVv0DKk8Q+JYcoZfOkLhYWNCXzlwTSRq8zGWayT1csjcpNXV9CQTBRRbmTLZac5cA==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.29.7.tgz", + "integrity": "sha512-bOMRLQuI0A5ZqHq3OWJ89/rXpJ/NJrbVhXiP4zwPGMs6kpcVsuTUNjwoE30K0Qm3mf48a/TnRYYD6vPNqcg6jA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-constant-elements": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.29.7.tgz", + "integrity": "sha512-J0wGhKan+rIiE2OhfhRptySLrJ6SjQYM6b6N1FMlhyhCcw1Mig8vQjWchyB+bgHGDvaWo6Diu6CLRMra2uMtmg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-display-name": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.29.7.tgz", + "integrity": "sha512-+1wdDMGNb4UPeY3Q4L5yLiYe6TXPXubs4NjrgRFw13hPRLJfEMw2Q5OXkee6/IfdqePIeW4Jjwe3aBh7SdKz4Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.29.7.tgz", + "integrity": "sha512-WsZulLVBUHXVj2cUcPVx6UE21TpalB6bHbSFErKT0Ib++ax24jjXe73FqlWvdylFOjiuPHYi6VCcgRad1ItN+A==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/plugin-syntax-jsx": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-development": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.29.7.tgz", + "integrity": "sha512-Xfy3UVMF04+ypnFbkhvfqtmvwfe92qwQdbGZVonhE+6v35GzlofmOnA1szaZqzb9xYWr0nl1e5EMmzi0DNON1g==", + "dev": true, + "dependencies": { + "@babel/plugin-transform-react-jsx": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-pure-annotations": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.29.7.tgz", + "integrity": "sha512-H5E+HBgDpr6Q5t+Aj11tL7XkIui1jhbIoArVQnqjgXo5/3YxkN7ZEBcWF4RQlB0T4rrxJQbXS6kiFV6B7XTqUA==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.29.7.tgz", + "integrity": "sha512-rNNFV0DBAJp988xW2DOntfDoYn1eR8GGF5AT5vYc+rjyfaQkM242c9tZUHHPe7KYaiJizXPWhQTzzdbXySyhBw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regexp-modifiers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.29.7.tgz", + "integrity": "sha512-mB5Fs0VWrJ42ZCmc8114v60qetdaUVNkj9PmSZRmanCZM3S9hm0CFRLjRmYIsuXav14l2jvZ+4T8iiCGnhj3nQ==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.29.7.tgz", + "integrity": "sha512-5+YhdpVgmfSmwZyLMftfaiffLRMHjzIRHFHHLdibcSyJm2pasMrKHrO3Ptrt2DRshjvpgjEJJ1zVW14WPq/6QA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.25.7.tgz", + "integrity": "sha512-Y9p487tyTzB0yDYQOtWnC+9HGOuogtP3/wNpun1xJXEEvI6vip59BSBTsHnekZLqxmPcgsrAKt46HAAb//xGhg==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7", + "babel-plugin-polyfill-corejs2": "^0.4.10", + "babel-plugin-polyfill-corejs3": "^0.10.6", + "babel-plugin-polyfill-regenerator": "^0.6.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime/node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.10.6", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.6.tgz", + "integrity": "sha512-b37+KR2i/khY5sKmWNVQAnitvquQbNdWy6lJdsr0kmquCKEEUgMKK4SboVM3HtfnZilfjr4MMQ7vY58FVWDtIA==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.2", + "core-js-compat": "^3.38.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.29.7.tgz", + "integrity": "sha512-I+WYbGBAiCn7nA6xBrlgPH+MB7HWb4u8pv5S0Pv7OtwNvIFvCCb24YlttKEeUFVurfBCEaOTnuhlqsb7f0Z5Dg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.29.7.tgz", + "integrity": "sha512-/u5K1QWada7tbYNqTjMh96718g9NTwh9tfPJMsSmVsQwGT447FskV+KcfeXkXq2GWki4EM/MuTdmBec+hOuVTQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.29.7.tgz", + "integrity": "sha512-BCHzNYJGe9l7EpwwDBN/ztlL2NYFFq8hp9ddjtUEM9f2O7S7kKV/lL6Fwo7IF7NSkYhPK2vO+86nIGltA90MsA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.29.7.tgz", + "integrity": "sha512-NCSEJ4sLFU2gqAub45HYh4fus2yQ36rr6ei6vpU7NdoJqCpxvEG8E6eJpscGyXP3VHD2Ny+fSXr04k1hoUrFqA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.29.7.tgz", + "integrity": "sha512-223mNGoTkBiTEWFoK+Q6Go3tueMRclO8vxxxxquNCYuNI4jWOofFKJRRDu6SDrB8Sgo1UEGW9T4GAQ8ZyRso1A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.29.7.tgz", + "integrity": "sha512-jK52h8LaLc7JarhQV2ofeFMts4H7vnOXnqZNA6fYglBTZewRBE51KWt3BUltW1P+KoPsYkHoJeXePuz4zo2LMw==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7", + "@babel/plugin-syntax-typescript": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.29.7.tgz", + "integrity": "sha512-jCfXxSjf94lf4E0hKE0AByxF6F3/pVFqRdUUNkDJhsY0m1ZKjnN6ZYyMeHNpzflxb/0q5b7t3p+BE+SLF1WOtA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.29.7.tgz", + "integrity": "sha512-OgZ+zoAJgZLUCunsTRQ5LAjOywDv5zzZ2/hQ5aMw1pGXyY2rtE8/chXYUmu3AlVHKpm10KEdG9aMwbI/K76ZGw==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.29.7.tgz", + "integrity": "sha512-7D/x/23/d/3VqZ0QA+LGbZMlGwZjztBygSWWWsfTPoQ1oQ6Q1P6Mr3d0kk42XabyUVw+fha3LqdRsFqeKqvCyA==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.29.7.tgz", + "integrity": "sha512-BLOhLht9DOJwIxlmp91wHvkXv1lguuHS3/FwUO8HL1H0u8s4hR1gASVFyilu9iGtcTRYqjTZmlsFFeQletntEg==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.29.7.tgz", + "integrity": "sha512-GYzX36n1nsciIb0uyH0GHwxwtNwPQIcpxSeiVLDtG/B7jB5xXgchnmL1f/jCX5o+pwnaDBtO60ONSJhEBJfxYA==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.29.7", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.29.7", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.29.7", + "@babel/plugin-bugfix-safari-rest-destructuring-rhs-array": "^7.29.7", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.29.7", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.29.7", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-import-assertions": "^7.29.7", + "@babel/plugin-syntax-import-attributes": "^7.29.7", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.29.7", + "@babel/plugin-transform-async-generator-functions": "^7.29.7", + "@babel/plugin-transform-async-to-generator": "^7.29.7", + "@babel/plugin-transform-block-scoped-functions": "^7.29.7", + "@babel/plugin-transform-block-scoping": "^7.29.7", + "@babel/plugin-transform-class-properties": "^7.29.7", + "@babel/plugin-transform-class-static-block": "^7.29.7", + "@babel/plugin-transform-classes": "^7.29.7", + "@babel/plugin-transform-computed-properties": "^7.29.7", + "@babel/plugin-transform-destructuring": "^7.29.7", + "@babel/plugin-transform-dotall-regex": "^7.29.7", + "@babel/plugin-transform-duplicate-keys": "^7.29.7", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.29.7", + "@babel/plugin-transform-dynamic-import": "^7.29.7", + "@babel/plugin-transform-explicit-resource-management": "^7.29.7", + "@babel/plugin-transform-exponentiation-operator": "^7.29.7", + "@babel/plugin-transform-export-namespace-from": "^7.29.7", + "@babel/plugin-transform-for-of": "^7.29.7", + "@babel/plugin-transform-function-name": "^7.29.7", + "@babel/plugin-transform-json-strings": "^7.29.7", + "@babel/plugin-transform-literals": "^7.29.7", + "@babel/plugin-transform-logical-assignment-operators": "^7.29.7", + "@babel/plugin-transform-member-expression-literals": "^7.29.7", + "@babel/plugin-transform-modules-amd": "^7.29.7", + "@babel/plugin-transform-modules-commonjs": "^7.29.7", + "@babel/plugin-transform-modules-systemjs": "^7.29.7", + "@babel/plugin-transform-modules-umd": "^7.29.7", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.29.7", + "@babel/plugin-transform-new-target": "^7.29.7", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.29.7", + "@babel/plugin-transform-numeric-separator": "^7.29.7", + "@babel/plugin-transform-object-rest-spread": "^7.29.7", + "@babel/plugin-transform-object-super": "^7.29.7", + "@babel/plugin-transform-optional-catch-binding": "^7.29.7", + "@babel/plugin-transform-optional-chaining": "^7.29.7", + "@babel/plugin-transform-parameters": "^7.29.7", + "@babel/plugin-transform-private-methods": "^7.29.7", + "@babel/plugin-transform-private-property-in-object": "^7.29.7", + "@babel/plugin-transform-property-literals": "^7.29.7", + "@babel/plugin-transform-regenerator": "^7.29.7", + "@babel/plugin-transform-regexp-modifiers": "^7.29.7", + "@babel/plugin-transform-reserved-words": "^7.29.7", + "@babel/plugin-transform-shorthand-properties": "^7.29.7", + "@babel/plugin-transform-spread": "^7.29.7", + "@babel/plugin-transform-sticky-regex": "^7.29.7", + "@babel/plugin-transform-template-literals": "^7.29.7", + "@babel/plugin-transform-typeof-symbol": "^7.29.7", + "@babel/plugin-transform-unicode-escapes": "^7.29.7", + "@babel/plugin-transform-unicode-property-regex": "^7.29.7", + "@babel/plugin-transform-unicode-regex": "^7.29.7", + "@babel/plugin-transform-unicode-sets-regex": "^7.29.7", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.15", + "babel-plugin-polyfill-corejs3": "^0.14.0", + "babel-plugin-polyfill-regenerator": "^0.6.6", + "core-js-compat": "^3.48.0", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/preset-react": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.29.7.tgz", + "integrity": "sha512-C+PV1TFUPTmBQGoPBL8j2QmLpZ117YTCwxIZeJOM96GbYMFSc7/pOXU5lVykwnZxyTqQxRsvoRk6f2FktZgGHA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "@babel/plugin-transform-react-display-name": "^7.29.7", + "@babel/plugin-transform-react-jsx": "^7.29.7", + "@babel/plugin-transform-react-jsx-development": "^7.29.7", + "@babel/plugin-transform-react-pure-annotations": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-typescript": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.29.7.tgz", + "integrity": "sha512-/Foi8vKY2EVbed/1eZx0gJEEwHAIxogrySI7rULcRIvhZzbvoE/b5qG5Ghc0WKAFKOHA9SD1x7RsFlOYdutIiQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "@babel/plugin-syntax-jsx": "^7.29.7", + "@babel/plugin-transform-modules-commonjs": "^7.29.7", + "@babel/plugin-transform-typescript": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.7.tgz", + "integrity": "sha512-FjoyLe754PMiYsFaN5C94ttGiOmBNYTf6pLr4xXHAT5uctHb092PBszndLDR5XA/jghQvn4n7JMHl7dmTgbm9w==", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz", + "integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true + }, + "node_modules/@cacheable/memory": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@cacheable/memory/-/memory-2.0.9.tgz", + "integrity": "sha512-HdMx6DoGywB30vacDbBsITbIX4pgFqj1zsrV58jZBUw3klzkNoXhj7qOqAgledhxG7YZI5rBSJg7Zp8/VG0DuA==", + "dev": true, + "dependencies": { + "@cacheable/utils": "^2.4.1", + "@keyv/bigmap": "^1.3.1", + "hookified": "^1.15.1", + "keyv": "^5.6.0" + } + }, + "node_modules/@cacheable/memory/node_modules/@keyv/bigmap": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@keyv/bigmap/-/bigmap-1.3.1.tgz", + "integrity": "sha512-WbzE9sdmQtKy8vrNPa9BRnwZh5UF4s1KTmSK0KUVLo3eff5BlQNNWDnFOouNpKfPKDnms9xynJjsMYjMaT/aFQ==", + "dev": true, + "dependencies": { + "hashery": "^1.4.0", + "hookified": "^1.15.0" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "keyv": "^5.6.0" + } + }, + "node_modules/@cacheable/memory/node_modules/keyv": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-5.6.0.tgz", + "integrity": "sha512-CYDD3SOtsHtyXeEORYRx2qBtpDJFjRTGXUtmNEMGyzYOKj1TE3tycdlho7kA1Ufx9OYWZzg52QFBGALTirzDSw==", + "dev": true, + "dependencies": { + "@keyv/serialize": "^1.1.1" + } + }, + "node_modules/@cacheable/utils": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@cacheable/utils/-/utils-2.4.1.tgz", + "integrity": "sha512-eiFgzCbIneyMlLOmNG4g9xzF7Hv3Mga4LjxjcSC/ues6VYq2+gUbQI8JqNuw/ZM8tJIeIaBGpswAsqV2V7ApgA==", + "dev": true, + "dependencies": { + "hashery": "^1.5.1", + "keyv": "^5.6.0" + } + }, + "node_modules/@cacheable/utils/node_modules/keyv": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-5.6.0.tgz", + "integrity": "sha512-CYDD3SOtsHtyXeEORYRx2qBtpDJFjRTGXUtmNEMGyzYOKj1TE3tycdlho7kA1Ufx9OYWZzg52QFBGALTirzDSw==", + "dev": true, + "dependencies": { + "@keyv/serialize": "^1.1.1" + } + }, + "node_modules/@csstools/css-parser-algorithms": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz", + "integrity": "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-syntax-patches-for-csstree": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.1.4.tgz", + "integrity": "sha512-wgsqt92b7C7tQhIdPNxj0n9zuUbQlvAuI1exyzeNrOKOi62SD7ren8zqszmpVREjAOqg8cD2FqYhQfAuKjk4sw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "peerDependencies": { + "css-tree": "^3.2.1" + }, + "peerDependenciesMeta": { + "css-tree": { + "optional": true + } + } + }, + "node_modules/@csstools/css-tokenizer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz", + "integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@csstools/media-query-list-parser": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-3.0.1.tgz", + "integrity": "sha512-HNo8gGD02kHmcbX6PvCoUuOQvn4szyB9ca63vZHKX5A81QytgDG4oxG4IaEfHTlEZSZ6MjPEMWIVU+zF2PZcgw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.1", + "@csstools/css-tokenizer": "^3.0.1" + } + }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@dual-bundle/import-meta-resolve": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@dual-bundle/import-meta-resolve/-/import-meta-resolve-4.2.1.tgz", + "integrity": "sha512-id+7YRUgoUX6CgV0DtuhirQWodeeA7Lf4i2x71JS/vtA5pRb/hIGWlw+G6MeXvsM+MXrz0VAydTGElX1rAfgPg==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/JounQin" + } + }, + "node_modules/@emnapi/core": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", + "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", + "dev": true, + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.1", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", + "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", + "dev": true, + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", + "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", + "dev": true, + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@es-joy/jsdoccomment": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.41.0.tgz", + "integrity": "sha512-aKUhyn1QI5Ksbqcr3fFJj16p99QdjUxXAEuFst1Z47DRyoiMwivIH9MV/ARcJOCXVjPfjITciej8ZD2O/6qUmw==", + "dev": true, + "dependencies": { + "comment-parser": "1.4.1", + "esquery": "^1.5.0", + "jsdoc-type-pratt-parser": "~4.0.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/js": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", + "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@formatjs/ecma402-abstract": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-2.3.6.tgz", + "integrity": "sha512-HJnTFeRM2kVFVr5gr5kH1XP6K0JcJtE7Lzvtr3FS/so5f1kpsqqqxy5JF+FRaO6H2qmcMfAUIox7AJteieRtVw==", + "dev": true, + "dependencies": { + "@formatjs/fast-memoize": "2.2.7", + "@formatjs/intl-localematcher": "0.6.2", + "decimal.js": "^10.4.3", + "tslib": "^2.8.0" + } + }, + "node_modules/@formatjs/fast-memoize": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/@formatjs/fast-memoize/-/fast-memoize-2.2.7.tgz", + "integrity": "sha512-Yabmi9nSvyOMrlSeGGWDiH7rf3a7sIwplbvo/dlz9WCIjzIQAfy1RMf4S0X3yG724n5Ghu2GmEl5NJIV6O9sZQ==", + "dev": true, + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@formatjs/icu-messageformat-parser": { + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.11.4.tgz", + "integrity": "sha512-7kR78cRrPNB4fjGFZg3Rmj5aah8rQj9KPzuLsmcSn4ipLXQvC04keycTI1F7kJYDwIXtT2+7IDEto842CfZBtw==", + "dev": true, + "dependencies": { + "@formatjs/ecma402-abstract": "2.3.6", + "@formatjs/icu-skeleton-parser": "1.8.16", + "tslib": "^2.8.0" + } + }, + "node_modules/@formatjs/icu-skeleton-parser": { + "version": "1.8.16", + "resolved": "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.8.16.tgz", + "integrity": "sha512-H13E9Xl+PxBd8D5/6TVUluSpxGNvFSlN/b3coUp0e0JpuWXXnQDiavIpY3NnvSp4xhEMoXyyBvVfdFX8jglOHQ==", + "dev": true, + "dependencies": { + "@formatjs/ecma402-abstract": "2.3.6", + "tslib": "^2.8.0" + } + }, + "node_modules/@formatjs/intl-localematcher": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.6.2.tgz", + "integrity": "sha512-XOMO2Hupl0wdd172Y06h6kLpBz6Dv+J4okPLl4LPtzbr8f66WbIoy4ev98EBuZ6ZK4h5ydTN6XneT4QVpD7cdA==", + "dev": true, + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@hapi/address": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@hapi/address/-/address-5.1.1.tgz", + "integrity": "sha512-A+po2d/dVoY7cYajycYI43ZbYMXukuopIsqCjh5QzsBCipDtdofHntljDlpccMjIfTy6UOkg+5KPriwYch2bXA==", + "dev": true, + "dependencies": { + "@hapi/hoek": "^11.0.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@hapi/formula": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@hapi/formula/-/formula-3.0.2.tgz", + "integrity": "sha512-hY5YPNXzw1He7s0iqkRQi+uMGh383CGdyyIGYtB+W5N3KHPXoqychklvHhKCC9M3Xtv0OCs/IHw+r4dcHtBYWw==", + "dev": true + }, + "node_modules/@hapi/hoek": { + "version": "11.0.7", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-11.0.7.tgz", + "integrity": "sha512-HV5undWkKzcB4RZUusqOpcgxOaq6VOAH7zhhIr2g3G8NF/MlFO75SjOr2NfuSx0Mh40+1FqCkagKLJRykUWoFQ==", + "dev": true + }, + "node_modules/@hapi/pinpoint": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@hapi/pinpoint/-/pinpoint-2.0.1.tgz", + "integrity": "sha512-EKQmr16tM8s16vTT3cA5L0kZZcTMU5DUOZTuvpnY738m+jyP3JIUj+Mm1xc1rsLkGBQ/gVnfKYPwOmPg1tUR4Q==", + "dev": true + }, + "node_modules/@hapi/tlds": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@hapi/tlds/-/tlds-1.1.6.tgz", + "integrity": "sha512-xdi7A/4NZokvV0ewovme3aUO5kQhW9pQ2YD1hRqZGhhSi5rBv4usHYidVocXSi9eihYsznZxLtAiEYYUL6VBGw==", + "dev": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@hapi/topo": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-6.0.2.tgz", + "integrity": "sha512-KR3rD5inZbGMrHmgPxsJ9dbi6zEK+C3ZwUwTa+eMwWLz7oijWUTWD2pMSNNYJAU6Qq+65NkxXjqHr/7LM2Xkqg==", + "dev": true, + "dependencies": { + "@hapi/hoek": "^11.0.2" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", + "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", + "deprecated": "Use @eslint/config-array instead", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.3", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "deprecated": "Use @eslint/object-schema instead", + "dev": true + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.6.tgz", + "integrity": "sha512-+Sg6GCR/wy1oSmQDFq4LQDAhm3ETKnorxN+y5nbLULOR3P0c14f2Wurzj3/xqPXtasLFfHd5iRFQ7AJt4KH2cw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", + "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", + "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", + "dev": true, + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/reporters": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^29.7.0", + "jest-config": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-resolve-dependencies": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "jest-watcher": "^29.7.0", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/environment": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", + "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", + "dev": true, + "dependencies": { + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", + "dev": true, + "dependencies": { + "expect": "^29.7.0", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", + "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", + "dev": true, + "dependencies": { + "jest-get-type": "^29.6.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", + "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", + "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/types": "^29.6.3", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/reporters": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", + "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", + "dev": true, + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^6.0.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", + "v8-to-istanbul": "^9.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/reporters/node_modules/istanbul-lib-instrument": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", + "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", + "dev": true, + "dependencies": { + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@jest/reporters/node_modules/semver": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz", + "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", + "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.18", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-result": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", + "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", + "dev": true, + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", + "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", + "dev": true, + "dependencies": { + "@jest/test-result": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", + "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@keyv/serialize": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@keyv/serialize/-/serialize-1.1.1.tgz", + "integrity": "sha512-dXn3FZhPv0US+7dtJsIi2R+c7qWYiReoEh5zUntWCf4oSpMNib8FDhSoed6m3QyZdx5hK7iLFkYk3rNxwt8vTA==", + "dev": true + }, + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", + "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", + "dev": true + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", + "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==", + "dev": true, + "optional": true, + "dependencies": { + "@tybys/wasm-util": "^0.10.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" + } + }, + "node_modules/@nicolo-ribaudo/eslint-scope-5-internals": { + "version": "5.1.1-v1", + "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", + "integrity": "sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==", + "dev": true, + "dependencies": { + "eslint-scope": "5.1.1" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@opentelemetry/api": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.1.tgz", + "integrity": "sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==", + "dev": true, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@opentelemetry/api-logs": { + "version": "0.57.2", + "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.57.2.tgz", + "integrity": "sha512-uIX52NnTM0iBh84MShlpouI7UKqkZ7MrUszTmaypHBu4r7NofznSnQRfJ+uUeDtQDj6w8eFGg5KBLDAwAPz1+A==", + "dev": true, + "dependencies": { + "@opentelemetry/api": "^1.3.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@opentelemetry/context-async-hooks": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/context-async-hooks/-/context-async-hooks-1.30.1.tgz", + "integrity": "sha512-s5vvxXPVdjqS3kTLKMeBMvop9hbWkwzBpu+mUO2M7sZtlkyDJGwFe33wRKnbaYDo8ExRVBIIdwIGrqpxHuKttA==", + "dev": true, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/core": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.30.1.tgz", + "integrity": "sha512-OOCM2C/QIURhJMuKaekP3TRBxBKxG/TWWA0TL2J6nXUtDnuCtccy49LUJF8xPFXMX+0LMcxFpCo8M9cGY1W6rQ==", + "dev": true, + "dependencies": { + "@opentelemetry/semantic-conventions": "1.28.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/core/node_modules/@opentelemetry/semantic-conventions": { + "version": "1.28.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.28.0.tgz", + "integrity": "sha512-lp4qAiMTD4sNWW4DbKLBkfiMZ4jbAboJIGOQr5DvciMRI494OapieI9qiODpOt0XBr1LjIDy1xAGAnVs5supTA==", + "dev": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@opentelemetry/instrumentation": { + "version": "0.57.2", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation/-/instrumentation-0.57.2.tgz", + "integrity": "sha512-BdBGhQBh8IjZ2oIIX6F2/Q3LKm/FDDKi6ccYKcBTeilh6SNdNKveDOLk73BkSJjQLJk6qe4Yh+hHw1UPhCDdrg==", + "dev": true, + "dependencies": { + "@opentelemetry/api-logs": "0.57.2", + "@types/shimmer": "^1.2.0", + "import-in-the-middle": "^1.8.1", + "require-in-the-middle": "^7.1.1", + "semver": "^7.5.2", + "shimmer": "^1.2.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-amqplib": { + "version": "0.46.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-amqplib/-/instrumentation-amqplib-0.46.1.tgz", + "integrity": "sha512-AyXVnlCf/xV3K/rNumzKxZqsULyITJH6OVLiW6730JPRqWA7Zc9bvYoVNpN6iOpTU8CasH34SU/ksVJmObFibQ==", + "dev": true, + "dependencies": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.57.1", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-connect": { + "version": "0.43.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-connect/-/instrumentation-connect-0.43.1.tgz", + "integrity": "sha512-ht7YGWQuV5BopMcw5Q2hXn3I8eG8TH0J/kc/GMcW4CuNTgiP6wCu44BOnucJWL3CmFWaRHI//vWyAhaC8BwePw==", + "dev": true, + "dependencies": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.57.1", + "@opentelemetry/semantic-conventions": "^1.27.0", + "@types/connect": "3.4.38" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-dataloader": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-dataloader/-/instrumentation-dataloader-0.16.1.tgz", + "integrity": "sha512-K/qU4CjnzOpNkkKO4DfCLSQshejRNAJtd4esgigo/50nxCB6XCyi1dhAblUHM9jG5dRm8eu0FB+t87nIo99LYQ==", + "dev": true, + "dependencies": { + "@opentelemetry/instrumentation": "^0.57.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-express": { + "version": "0.47.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-express/-/instrumentation-express-0.47.1.tgz", + "integrity": "sha512-QNXPTWteDclR2B4pDFpz0TNghgB33UMjUt14B+BZPmtH1MwUFAfLHBaP5If0Z5NZC+jaH8oF2glgYjrmhZWmSw==", + "dev": true, + "dependencies": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.57.1", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-fs": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-fs/-/instrumentation-fs-0.19.1.tgz", + "integrity": "sha512-6g0FhB3B9UobAR60BGTcXg4IHZ6aaYJzp0Ki5FhnxyAPt8Ns+9SSvgcrnsN2eGmk3RWG5vYycUGOEApycQL24A==", + "dev": true, + "dependencies": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.57.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-generic-pool": { + "version": "0.43.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-generic-pool/-/instrumentation-generic-pool-0.43.1.tgz", + "integrity": "sha512-M6qGYsp1cURtvVLGDrPPZemMFEbuMmCXgQYTReC/IbimV5sGrLBjB+/hANUpRZjX67nGLdKSVLZuQQAiNz+sww==", + "dev": true, + "dependencies": { + "@opentelemetry/instrumentation": "^0.57.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-graphql": { + "version": "0.47.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-graphql/-/instrumentation-graphql-0.47.1.tgz", + "integrity": "sha512-EGQRWMGqwiuVma8ZLAZnExQ7sBvbOx0N/AE/nlafISPs8S+QtXX+Viy6dcQwVWwYHQPAcuY3bFt3xgoAwb4ZNQ==", + "dev": true, + "dependencies": { + "@opentelemetry/instrumentation": "^0.57.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-hapi": { + "version": "0.45.2", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-hapi/-/instrumentation-hapi-0.45.2.tgz", + "integrity": "sha512-7Ehow/7Wp3aoyCrZwQpU7a2CnoMq0XhIcioFuKjBb0PLYfBfmTsFTUyatlHu0fRxhwcRsSQRTvEhmZu8CppBpQ==", + "dev": true, + "dependencies": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.57.1", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-http": { + "version": "0.57.2", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-http/-/instrumentation-http-0.57.2.tgz", + "integrity": "sha512-1Uz5iJ9ZAlFOiPuwYg29Bf7bJJc/GeoeJIFKJYQf67nTVKFe8RHbEtxgkOmK4UGZNHKXcpW4P8cWBYzBn1USpg==", + "dev": true, + "dependencies": { + "@opentelemetry/core": "1.30.1", + "@opentelemetry/instrumentation": "0.57.2", + "@opentelemetry/semantic-conventions": "1.28.0", + "forwarded-parse": "2.1.2", + "semver": "^7.5.2" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-http/node_modules/@opentelemetry/semantic-conventions": { + "version": "1.28.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.28.0.tgz", + "integrity": "sha512-lp4qAiMTD4sNWW4DbKLBkfiMZ4jbAboJIGOQr5DvciMRI494OapieI9qiODpOt0XBr1LjIDy1xAGAnVs5supTA==", + "dev": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@opentelemetry/instrumentation-http/node_modules/semver": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz", + "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@opentelemetry/instrumentation-ioredis": { + "version": "0.47.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-ioredis/-/instrumentation-ioredis-0.47.1.tgz", + "integrity": "sha512-OtFGSN+kgk/aoKgdkKQnBsQFDiG8WdCxu+UrHr0bXScdAmtSzLSraLo7wFIb25RVHfRWvzI5kZomqJYEg/l1iA==", + "dev": true, + "dependencies": { + "@opentelemetry/instrumentation": "^0.57.1", + "@opentelemetry/redis-common": "^0.36.2", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-kafkajs": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-kafkajs/-/instrumentation-kafkajs-0.7.1.tgz", + "integrity": "sha512-OtjaKs8H7oysfErajdYr1yuWSjMAectT7Dwr+axIoZqT9lmEOkD/H/3rgAs8h/NIuEi2imSXD+vL4MZtOuJfqQ==", + "dev": true, + "dependencies": { + "@opentelemetry/instrumentation": "^0.57.1", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-knex": { + "version": "0.44.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-knex/-/instrumentation-knex-0.44.1.tgz", + "integrity": "sha512-U4dQxkNhvPexffjEmGwCq68FuftFK15JgUF05y/HlK3M6W/G2iEaACIfXdSnwVNe9Qh0sPfw8LbOPxrWzGWGMQ==", + "dev": true, + "dependencies": { + "@opentelemetry/instrumentation": "^0.57.1", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-koa": { + "version": "0.47.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-koa/-/instrumentation-koa-0.47.1.tgz", + "integrity": "sha512-l/c+Z9F86cOiPJUllUCt09v+kICKvT+Vg1vOAJHtHPsJIzurGayucfCMq2acd/A/yxeNWunl9d9eqZ0G+XiI6A==", + "dev": true, + "dependencies": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.57.1", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-lru-memoizer": { + "version": "0.44.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-lru-memoizer/-/instrumentation-lru-memoizer-0.44.1.tgz", + "integrity": "sha512-5MPkYCvG2yw7WONEjYj5lr5JFehTobW7wX+ZUFy81oF2lr9IPfZk9qO+FTaM0bGEiymwfLwKe6jE15nHn1nmHg==", + "dev": true, + "dependencies": { + "@opentelemetry/instrumentation": "^0.57.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-mongodb": { + "version": "0.52.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mongodb/-/instrumentation-mongodb-0.52.0.tgz", + "integrity": "sha512-1xmAqOtRUQGR7QfJFfGV/M2kC7wmI2WgZdpru8hJl3S0r4hW0n3OQpEHlSGXJAaNFyvT+ilnwkT+g5L4ljHR6g==", + "dev": true, + "dependencies": { + "@opentelemetry/instrumentation": "^0.57.1", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-mongoose": { + "version": "0.46.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mongoose/-/instrumentation-mongoose-0.46.1.tgz", + "integrity": "sha512-3kINtW1LUTPkiXFRSSBmva1SXzS/72we/jL22N+BnF3DFcoewkdkHPYOIdAAk9gSicJ4d5Ojtt1/HeibEc5OQg==", + "dev": true, + "dependencies": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.57.1", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-mysql": { + "version": "0.45.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mysql/-/instrumentation-mysql-0.45.1.tgz", + "integrity": "sha512-TKp4hQ8iKQsY7vnp/j0yJJ4ZsP109Ht6l4RHTj0lNEG1TfgTrIH5vJMbgmoYXWzNHAqBH2e7fncN12p3BP8LFg==", + "dev": true, + "dependencies": { + "@opentelemetry/instrumentation": "^0.57.1", + "@opentelemetry/semantic-conventions": "^1.27.0", + "@types/mysql": "2.15.26" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-mysql2": { + "version": "0.45.2", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mysql2/-/instrumentation-mysql2-0.45.2.tgz", + "integrity": "sha512-h6Ad60FjCYdJZ5DTz1Lk2VmQsShiViKe0G7sYikb0GHI0NVvApp2XQNRHNjEMz87roFttGPLHOYVPlfy+yVIhQ==", + "dev": true, + "dependencies": { + "@opentelemetry/instrumentation": "^0.57.1", + "@opentelemetry/semantic-conventions": "^1.27.0", + "@opentelemetry/sql-common": "^0.40.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-pg": { + "version": "0.51.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-pg/-/instrumentation-pg-0.51.1.tgz", + "integrity": "sha512-QxgjSrxyWZc7Vk+qGSfsejPVFL1AgAJdSBMYZdDUbwg730D09ub3PXScB9d04vIqPriZ+0dqzjmQx0yWKiCi2Q==", + "dev": true, + "dependencies": { + "@opentelemetry/core": "^1.26.0", + "@opentelemetry/instrumentation": "^0.57.1", + "@opentelemetry/semantic-conventions": "^1.27.0", + "@opentelemetry/sql-common": "^0.40.1", + "@types/pg": "8.6.1", + "@types/pg-pool": "2.0.6" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-redis-4": { + "version": "0.46.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-redis-4/-/instrumentation-redis-4-0.46.1.tgz", + "integrity": "sha512-UMqleEoabYMsWoTkqyt9WAzXwZ4BlFZHO40wr3d5ZvtjKCHlD4YXLm+6OLCeIi/HkX7EXvQaz8gtAwkwwSEvcQ==", + "dev": true, + "dependencies": { + "@opentelemetry/instrumentation": "^0.57.1", + "@opentelemetry/redis-common": "^0.36.2", + "@opentelemetry/semantic-conventions": "^1.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-tedious": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-tedious/-/instrumentation-tedious-0.18.1.tgz", + "integrity": "sha512-5Cuy/nj0HBaH+ZJ4leuD7RjgvA844aY2WW+B5uLcWtxGjRZl3MNLuxnNg5DYWZNPO+NafSSnra0q49KWAHsKBg==", + "dev": true, + "dependencies": { + "@opentelemetry/instrumentation": "^0.57.1", + "@opentelemetry/semantic-conventions": "^1.27.0", + "@types/tedious": "^4.0.14" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-undici": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-undici/-/instrumentation-undici-0.10.1.tgz", + "integrity": "sha512-rkOGikPEyRpMCmNu9AQuV5dtRlDmJp2dK5sw8roVshAGoB6hH/3QjDtRhdwd75SsJwgynWUNRUYe0wAkTo16tQ==", + "dev": true, + "dependencies": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.57.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.7.0" + } + }, + "node_modules/@opentelemetry/instrumentation/node_modules/semver": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz", + "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@opentelemetry/redis-common": { + "version": "0.36.2", + "resolved": "https://registry.npmjs.org/@opentelemetry/redis-common/-/redis-common-0.36.2.tgz", + "integrity": "sha512-faYX1N0gpLhej/6nyp6bgRjzAKXn5GOEMYY7YhciSfCoITAktLUtQ36d24QEWNA1/WA1y6qQunCe0OhHRkVl9g==", + "dev": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@opentelemetry/resources": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.30.1.tgz", + "integrity": "sha512-5UxZqiAgLYGFjS4s9qm5mBVo433u+dSPUFWVWXmLAD4wB65oMCoXaJP1KJa9DIYYMeHu3z4BZcStG3LC593cWA==", + "dev": true, + "dependencies": { + "@opentelemetry/core": "1.30.1", + "@opentelemetry/semantic-conventions": "1.28.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/resources/node_modules/@opentelemetry/semantic-conventions": { + "version": "1.28.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.28.0.tgz", + "integrity": "sha512-lp4qAiMTD4sNWW4DbKLBkfiMZ4jbAboJIGOQr5DvciMRI494OapieI9qiODpOt0XBr1LjIDy1xAGAnVs5supTA==", + "dev": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@opentelemetry/sdk-trace-base": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.30.1.tgz", + "integrity": "sha512-jVPgBbH1gCy2Lb7X0AVQ8XAfgg0pJ4nvl8/IiQA6nxOsPvS+0zMJaFSs2ltXe0J6C8dqjcnpyqINDJmU30+uOg==", + "dev": true, + "dependencies": { + "@opentelemetry/core": "1.30.1", + "@opentelemetry/resources": "1.30.1", + "@opentelemetry/semantic-conventions": "1.28.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-trace-base/node_modules/@opentelemetry/semantic-conventions": { + "version": "1.28.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.28.0.tgz", + "integrity": "sha512-lp4qAiMTD4sNWW4DbKLBkfiMZ4jbAboJIGOQr5DvciMRI494OapieI9qiODpOt0XBr1LjIDy1xAGAnVs5supTA==", + "dev": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@opentelemetry/semantic-conventions": { + "version": "1.41.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.41.1.tgz", + "integrity": "sha512-/UhIkaZgPutTFmQ7RnIJGgDXZmtEJ7Dvi86xNTFWcnRxVRNk/aotsqDJYeEvDP+FSMB2SdW+pQzNMcWP0rwuNA==", + "dev": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@opentelemetry/sql-common": { + "version": "0.40.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sql-common/-/sql-common-0.40.1.tgz", + "integrity": "sha512-nSDlnHSqzC3pXn/wZEZVLuAuJ1MYMXPBwtv2qAbCa3847SaHItdE7SzUq/Jtb0KZmh1zfAbNi3AAMjztTT4Ugg==", + "dev": true, + "dependencies": { + "@opentelemetry/core": "^1.1.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.1.0" + } + }, + "node_modules/@parcel/watcher": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.6.tgz", + "integrity": "sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "dependencies": { + "detect-libc": "^2.0.3", + "is-glob": "^4.0.3", + "node-addon-api": "^7.0.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "@parcel/watcher-android-arm64": "2.5.6", + "@parcel/watcher-darwin-arm64": "2.5.6", + "@parcel/watcher-darwin-x64": "2.5.6", + "@parcel/watcher-freebsd-x64": "2.5.6", + "@parcel/watcher-linux-arm-glibc": "2.5.6", + "@parcel/watcher-linux-arm-musl": "2.5.6", + "@parcel/watcher-linux-arm64-glibc": "2.5.6", + "@parcel/watcher-linux-arm64-musl": "2.5.6", + "@parcel/watcher-linux-x64-glibc": "2.5.6", + "@parcel/watcher-linux-x64-musl": "2.5.6", + "@parcel/watcher-win32-arm64": "2.5.6", + "@parcel/watcher-win32-ia32": "2.5.6", + "@parcel/watcher-win32-x64": "2.5.6" + } + }, + "node_modules/@parcel/watcher-android-arm64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.6.tgz", + "integrity": "sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-arm64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.6.tgz", + "integrity": "sha512-Z2ZdrnwyXvvvdtRHLmM4knydIdU9adO3D4n/0cVipF3rRiwP+3/sfzpAwA/qKFL6i1ModaabkU7IbpeMBgiVEA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-x64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.6.tgz", + "integrity": "sha512-HgvOf3W9dhithcwOWX9uDZyn1lW9R+7tPZ4sug+NGrGIo4Rk1hAXLEbcH1TQSqxts0NYXXlOWqVpvS1SFS4fRg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-freebsd-x64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.6.tgz", + "integrity": "sha512-vJVi8yd/qzJxEKHkeemh7w3YAn6RJCtYlE4HPMoVnCpIXEzSrxErBW5SJBgKLbXU3WdIpkjBTeUNtyBVn8TRng==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-glibc": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.6.tgz", + "integrity": "sha512-9JiYfB6h6BgV50CCfasfLf/uvOcJskMSwcdH1PHH9rvS1IrNy8zad6IUVPVUfmXr+u+Km9IxcfMLzgdOudz9EQ==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-musl": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.6.tgz", + "integrity": "sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-glibc": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.6.tgz", + "integrity": "sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-musl": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.6.tgz", + "integrity": "sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-glibc": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.6.tgz", + "integrity": "sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-musl": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.6.tgz", + "integrity": "sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-arm64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.6.tgz", + "integrity": "sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-ia32": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.6.tgz", + "integrity": "sha512-k35yLp1ZMwwee3Ez/pxBi5cf4AoBKYXj00CZ80jUz5h8prpiaQsiRPKQMxoLstNuqe2vR4RNPEAEcjEFzhEz/g==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-x64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.6.tgz", + "integrity": "sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "optional": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@paulirish/trace_engine": { + "version": "0.0.59", + "resolved": "https://registry.npmjs.org/@paulirish/trace_engine/-/trace_engine-0.0.59.tgz", + "integrity": "sha512-439NUzQGmH+9Y017/xCchBP9571J4bzhpcNhrxorf7r37wcyJZkgUfrUsRL3xl+JDcZ6ORhoFCzCw98c6S3YHw==", + "dev": true, + "dependencies": { + "legacy-javascript": "latest", + "third-party-web": "latest" + } + }, + "node_modules/@pkgr/core": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz", + "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/pkgr" + } + }, + "node_modules/@playwright/test": { + "version": "1.60.0", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.60.0.tgz", + "integrity": "sha512-O71yZIbAh/PxDMNGns37GHBIfrVkEVyn+AXyIa5dOTfb4/xNvRWV+Vv/NMbNCtODB/pO7vLlF2OTmMVLhmr7Ag==", + "dev": true, + "peer": true, + "dependencies": { + "playwright": "1.60.0" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@pmmmwh/react-refresh-webpack-plugin": { + "version": "0.5.17", + "resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.17.tgz", + "integrity": "sha512-tXDyE1/jzFsHXjhRZQ3hMl0IVhYe5qula43LDWIhVfjp9G/nT5OQY5AORVOrkEGAUltBJOfOWeETbmhm6kHhuQ==", + "dev": true, + "dependencies": { + "ansi-html": "^0.0.9", + "core-js-pure": "^3.23.3", + "error-stack-parser": "^2.0.6", + "html-entities": "^2.1.0", + "loader-utils": "^2.0.4", + "schema-utils": "^4.2.0", + "source-map": "^0.7.3" + }, + "engines": { + "node": ">= 10.13" + }, + "peerDependencies": { + "@types/webpack": "4.x || 5.x", + "react-refresh": ">=0.10.0 <1.0.0", + "sockjs-client": "^1.4.0", + "type-fest": ">=0.17.0 <5.0.0", + "webpack": ">=4.43.0 <6.0.0", + "webpack-dev-server": "3.x || 4.x || 5.x", + "webpack-hot-middleware": "2.x", + "webpack-plugin-serve": "0.x || 1.x" + }, + "peerDependenciesMeta": { + "@types/webpack": { + "optional": true + }, + "sockjs-client": { + "optional": true + }, + "type-fest": { + "optional": true + }, + "webpack-dev-server": { + "optional": true + }, + "webpack-hot-middleware": { + "optional": true + }, + "webpack-plugin-serve": { + "optional": true + } + } + }, + "node_modules/@polka/url": { + "version": "1.0.0-next.29", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz", + "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==", + "dev": true + }, + "node_modules/@prisma/instrumentation": { + "version": "6.11.1", + "resolved": "https://registry.npmjs.org/@prisma/instrumentation/-/instrumentation-6.11.1.tgz", + "integrity": "sha512-mrZOev24EDhnefmnZX7WVVT7v+r9LttPRqf54ONvj6re4XMF7wFTpK2tLJi4XHB7fFp/6xhYbgRel8YV7gQiyA==", + "dev": true, + "dependencies": { + "@opentelemetry/instrumentation": "^0.52.0 || ^0.53.0 || ^0.54.0 || ^0.55.0 || ^0.56.0 || ^0.57.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.8" + } + }, + "node_modules/@puppeteer/browsers": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.6.1.tgz", + "integrity": "sha512-aBSREisdsGH890S2rQqK82qmQYU3uFpSH8wcZWHgHzl3LfzsxAKbLNiAG9mO8v1Y0UICBeClICxPJvyr0rcuxg==", + "dev": true, + "dependencies": { + "debug": "^4.4.0", + "extract-zip": "^2.0.1", + "progress": "^2.0.3", + "proxy-agent": "^6.5.0", + "semver": "^7.6.3", + "tar-fs": "^3.0.6", + "unbzip2-stream": "^1.4.3", + "yargs": "^17.7.2" + }, + "bin": { + "browsers": "lib/cjs/main-cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@puppeteer/browsers/node_modules/semver": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz", + "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@rtsao/scc": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", + "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==", + "dev": true + }, + "node_modules/@sentry/core": { + "version": "9.47.1", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-9.47.1.tgz", + "integrity": "sha512-KX62+qIt4xgy8eHKHiikfhz2p5fOciXd0Cl+dNzhgPFq8klq4MGMNaf148GB3M/vBqP4nw/eFvRMAayFCgdRQw==", + "dev": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@sentry/node": { + "version": "9.47.1", + "resolved": "https://registry.npmjs.org/@sentry/node/-/node-9.47.1.tgz", + "integrity": "sha512-CDbkasBz3fnWRKSFs6mmaRepM2pa+tbZkrqhPWifFfIkJDidtVW40p6OnquTvPXyPAszCnDZRnZT14xyvNmKPQ==", + "dev": true, + "dependencies": { + "@opentelemetry/api": "^1.9.0", + "@opentelemetry/context-async-hooks": "^1.30.1", + "@opentelemetry/core": "^1.30.1", + "@opentelemetry/instrumentation": "^0.57.2", + "@opentelemetry/instrumentation-amqplib": "^0.46.1", + "@opentelemetry/instrumentation-connect": "0.43.1", + "@opentelemetry/instrumentation-dataloader": "0.16.1", + "@opentelemetry/instrumentation-express": "0.47.1", + "@opentelemetry/instrumentation-fs": "0.19.1", + "@opentelemetry/instrumentation-generic-pool": "0.43.1", + "@opentelemetry/instrumentation-graphql": "0.47.1", + "@opentelemetry/instrumentation-hapi": "0.45.2", + "@opentelemetry/instrumentation-http": "0.57.2", + "@opentelemetry/instrumentation-ioredis": "0.47.1", + "@opentelemetry/instrumentation-kafkajs": "0.7.1", + "@opentelemetry/instrumentation-knex": "0.44.1", + "@opentelemetry/instrumentation-koa": "0.47.1", + "@opentelemetry/instrumentation-lru-memoizer": "0.44.1", + "@opentelemetry/instrumentation-mongodb": "0.52.0", + "@opentelemetry/instrumentation-mongoose": "0.46.1", + "@opentelemetry/instrumentation-mysql": "0.45.1", + "@opentelemetry/instrumentation-mysql2": "0.45.2", + "@opentelemetry/instrumentation-pg": "0.51.1", + "@opentelemetry/instrumentation-redis-4": "0.46.1", + "@opentelemetry/instrumentation-tedious": "0.18.1", + "@opentelemetry/instrumentation-undici": "0.10.1", + "@opentelemetry/resources": "^1.30.1", + "@opentelemetry/sdk-trace-base": "^1.30.1", + "@opentelemetry/semantic-conventions": "^1.34.0", + "@prisma/instrumentation": "6.11.1", + "@sentry/core": "9.47.1", + "@sentry/node-core": "9.47.1", + "@sentry/opentelemetry": "9.47.1", + "import-in-the-middle": "^1.14.2", + "minimatch": "^9.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@sentry/node-core": { + "version": "9.47.1", + "resolved": "https://registry.npmjs.org/@sentry/node-core/-/node-core-9.47.1.tgz", + "integrity": "sha512-7TEOiCGkyShJ8CKtsri9lbgMCbB+qNts2Xq37itiMPN2m+lIukK3OX//L8DC5nfKYZlgikrefS63/vJtm669hQ==", + "dev": true, + "dependencies": { + "@sentry/core": "9.47.1", + "@sentry/opentelemetry": "9.47.1", + "import-in-the-middle": "^1.14.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.9.0", + "@opentelemetry/context-async-hooks": "^1.30.1 || ^2.0.0", + "@opentelemetry/core": "^1.30.1 || ^2.0.0", + "@opentelemetry/instrumentation": ">=0.57.1 <1", + "@opentelemetry/resources": "^1.30.1 || ^2.0.0", + "@opentelemetry/sdk-trace-base": "^1.30.1 || ^2.0.0", + "@opentelemetry/semantic-conventions": "^1.34.0" + } + }, + "node_modules/@sentry/opentelemetry": { + "version": "9.47.1", + "resolved": "https://registry.npmjs.org/@sentry/opentelemetry/-/opentelemetry-9.47.1.tgz", + "integrity": "sha512-STtFpjF7lwzeoedDJV+5XA6P89BfmFwFftmHSGSe3UTI8z8IoiR5yB6X2vCjSPvXlfeOs13qCNNCEZyznxM8Xw==", + "dev": true, + "dependencies": { + "@sentry/core": "9.47.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.9.0", + "@opentelemetry/context-async-hooks": "^1.30.1 || ^2.0.0", + "@opentelemetry/core": "^1.30.1 || ^2.0.0", + "@opentelemetry/sdk-trace-base": "^1.30.1 || ^2.0.0", + "@opentelemetry/semantic-conventions": "^1.34.0" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.10", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.10.tgz", + "integrity": "sha512-MTBk/3jGLNB2tVxv6uLlFh1iu64iYOQ2PbdOSK3NW8JZsmlaOh2q6sdtKowBhfw8QFLmYNzTW4/oK4uATIi6ZA==", + "dev": true + }, + "node_modules/@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^3.0.0" + } + }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "dev": true + }, + "node_modules/@stylistic/stylelint-plugin": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@stylistic/stylelint-plugin/-/stylelint-plugin-3.1.3.tgz", + "integrity": "sha512-85fsmzgsIVmyG3/GFrjuYj6Cz8rAM7IZiPiXCMiSMfoDOC1lOrzrXPDk24WqviAghnPqGpx8b0caK2PuewWGFg==", + "dev": true, + "dependencies": { + "@csstools/css-parser-algorithms": "^3.0.1", + "@csstools/css-tokenizer": "^3.0.1", + "@csstools/media-query-list-parser": "^3.0.1", + "is-plain-object": "^5.0.0", + "postcss": "^8.4.41", + "postcss-selector-parser": "^6.1.2", + "postcss-value-parser": "^4.2.0", + "style-search": "^0.1.0" + }, + "engines": { + "node": "^18.12 || >=20.9" + }, + "peerDependencies": { + "stylelint": "^16.8.0" + } + }, + "node_modules/@svgr/babel-plugin-add-jsx-attribute": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-8.0.0.tgz", + "integrity": "sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-remove-jsx-attribute": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-8.0.0.tgz", + "integrity": "sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-remove-jsx-empty-expression": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-8.0.0.tgz", + "integrity": "sha512-5BcGCBfBxB5+XSDSWnhTThfI9jcO5f0Ai2V24gZpG+wXF14BzwxxdDb4g6trdOux0rhibGs385BeFMSmxtS3uA==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-replace-jsx-attribute-value": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-8.0.0.tgz", + "integrity": "sha512-KVQ+PtIjb1BuYT3ht8M5KbzWBhdAjjUPdlMtpuw/VjT8coTrItWX6Qafl9+ji831JaJcu6PJNKCV0bp01lBNzQ==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-svg-dynamic-title": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-8.0.0.tgz", + "integrity": "sha512-omNiKqwjNmOQJ2v6ge4SErBbkooV2aAWwaPFs2vUY7p7GhVkzRkJ00kILXQvRhA6miHnNpXv7MRnnSjdRjK8og==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-svg-em-dimensions": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-8.0.0.tgz", + "integrity": "sha512-mURHYnu6Iw3UBTbhGwE/vsngtCIbHE43xCRK7kCw4t01xyGqb2Pd+WXekRRoFOBIY29ZoOhUCTEweDMdrjfi9g==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-transform-react-native-svg": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-8.1.0.tgz", + "integrity": "sha512-Tx8T58CHo+7nwJ+EhUwx3LfdNSG9R2OKfaIXXs5soiy5HtgoAEkDay9LIimLOcG8dJQH1wPZp/cnAv6S9CrR1Q==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-plugin-transform-svg-component": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-8.0.0.tgz", + "integrity": "sha512-DFx8xa3cZXTdb/k3kfPeaixecQLgKh5NVBMwD0AQxOzcZawK4oo1Jh9LbrcACUivsCA7TLG8eeWgrDXjTMhRmw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/babel-preset": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/babel-preset/-/babel-preset-8.1.0.tgz", + "integrity": "sha512-7EYDbHE7MxHpv4sxvnVPngw5fuR6pw79SkcrILHJ/iMpuKySNCl5W1qcwPEpU+LgyRXOaAFgH0KhwD18wwg6ug==", + "dev": true, + "dependencies": { + "@svgr/babel-plugin-add-jsx-attribute": "8.0.0", + "@svgr/babel-plugin-remove-jsx-attribute": "8.0.0", + "@svgr/babel-plugin-remove-jsx-empty-expression": "8.0.0", + "@svgr/babel-plugin-replace-jsx-attribute-value": "8.0.0", + "@svgr/babel-plugin-svg-dynamic-title": "8.0.0", + "@svgr/babel-plugin-svg-em-dimensions": "8.0.0", + "@svgr/babel-plugin-transform-react-native-svg": "8.1.0", + "@svgr/babel-plugin-transform-svg-component": "8.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@svgr/core": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/core/-/core-8.1.0.tgz", + "integrity": "sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.21.3", + "@svgr/babel-preset": "8.1.0", + "camelcase": "^6.2.0", + "cosmiconfig": "^8.1.3", + "snake-case": "^3.0.4" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/hast-util-to-babel-ast": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-8.0.0.tgz", + "integrity": "sha512-EbDKwO9GpfWP4jN9sGdYwPBU0kdomaPIL2Eu4YwmgP+sJeXT+L7bMwJUBnhzfH8Q2qMBqZ4fJwpCyYsAN3mt2Q==", + "dev": true, + "dependencies": { + "@babel/types": "^7.21.3", + "entities": "^4.4.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@svgr/plugin-jsx": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-8.1.0.tgz", + "integrity": "sha512-0xiIyBsLlr8quN+WyuxooNW9RJ0Dpr8uOnH/xrCVO8GLUcwHISwj1AG0k+LFzteTkAA0GbX0kj9q6Dk70PTiPA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.21.3", + "@svgr/babel-preset": "8.1.0", + "@svgr/hast-util-to-babel-ast": "8.0.0", + "svg-parser": "^2.0.4" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@svgr/core": "*" + } + }, + "node_modules/@svgr/plugin-svgo": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-8.1.0.tgz", + "integrity": "sha512-Ywtl837OGO9pTLIN/onoWLmDQ4zFUycI1g76vuKGEz6evR/ZTJlJuz3G/fIkb6OVBJ2g0o6CGJzaEjfmEo3AHA==", + "dev": true, + "dependencies": { + "cosmiconfig": "^8.1.3", + "deepmerge": "^4.3.1", + "svgo": "^3.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + }, + "peerDependencies": { + "@svgr/core": "*" + } + }, + "node_modules/@svgr/webpack": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@svgr/webpack/-/webpack-8.1.0.tgz", + "integrity": "sha512-LnhVjMWyMQV9ZmeEy26maJk+8HTIbd59cH4F2MJ439k9DqejRisfFNGAPvRYlKETuh9LrImlS8aKsBgKjMA8WA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.21.3", + "@babel/plugin-transform-react-constant-elements": "^7.21.3", + "@babel/preset-env": "^7.20.2", + "@babel/preset-react": "^7.18.6", + "@babel/preset-typescript": "^7.21.0", + "@svgr/core": "8.1.0", + "@svgr/plugin-jsx": "8.1.0", + "@svgr/plugin-svgo": "8.1.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/gregberge" + } + }, + "node_modules/@tannin/compile": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@tannin/compile/-/compile-1.1.0.tgz", + "integrity": "sha512-n8m9eNDfoNZoxdvWiTfW/hSPhehzLJ3zW7f8E7oT6mCROoMNWCB4TYtv041+2FMAxweiE0j7i1jubQU4MEC/Gg==", + "dependencies": { + "@tannin/evaluate": "^1.2.0", + "@tannin/postfix": "^1.1.0" + } + }, + "node_modules/@tannin/evaluate": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@tannin/evaluate/-/evaluate-1.2.0.tgz", + "integrity": "sha512-3ioXvNowbO/wSrxsDG5DKIMxC81P0QrQTYai8zFNY+umuoHWRPbQ/TuuDEOju9E+jQDXmj6yI5GyejNuh8I+eg==" + }, + "node_modules/@tannin/plural-forms": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@tannin/plural-forms/-/plural-forms-1.1.0.tgz", + "integrity": "sha512-xl9R2mDZO/qiHam1AgMnAES6IKIg7OBhcXqy6eDsRCdXuxAFPcjrej9HMjyCLE0DJ/8cHf0i5OQTstuBRhpbHw==", + "dependencies": { + "@tannin/compile": "^1.1.0" + } + }, + "node_modules/@tannin/postfix": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@tannin/postfix/-/postfix-1.1.0.tgz", + "integrity": "sha512-oocsqY7g0cR+Gur5jRQLSrX2OtpMLMse1I10JQBm8CdGMrDkh1Mg2gjsiquMHRtBs4Qwu5wgEp5GgIYHk4SNPw==" + }, + "node_modules/@tannin/sprintf": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@tannin/sprintf/-/sprintf-1.3.3.tgz", + "integrity": "sha512-RwARl+hFwhzy0tg9atWcchLFvoQiOh4rrP7uG2N5E4W80BPCUX0ElcUR9St43fxB9EfjsW2df9Qp+UsTbvQDjA==" + }, + "node_modules/@tootallnate/once": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.1.tgz", + "integrity": "sha512-HqmEUIGRJ5fSXchkVgR5F7qn48bDBzv0kWj/Kfu5e6uci4UlEeng4331LnBkWffb++Ei3FOVLxo8JJWMFBDMeQ==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tootallnate/quickjs-emscripten": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", + "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==", + "dev": true + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz", + "integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==", + "dev": true, + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.6", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", + "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", + "dev": true, + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/bonjour": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.13.tgz", + "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect-history-api-fallback": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz", + "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==", + "dev": true, + "dependencies": { + "@types/express-serve-static-core": "*", + "@types/node": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "dev": true + }, + "node_modules/@types/express": { + "version": "4.17.25", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.25.tgz", + "integrity": "sha512-dVd04UKsfpINUnK0yBoYHDF3xu7xVH4BuDotC/xGuycx4CgbP48X/KF/586bcObxT0HENHXEU8Nqtu6NR+eKhw==", + "dev": true, + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "^1" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.1.1.tgz", + "integrity": "sha512-v4zIMr/cX7/d2BpAEX3KNKL/JrT1s43s96lLvvdTmza1oEvDudCqK9aF/djc/SWgy8Yh0h30TZx5VpzqFCxk5A==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/express/node_modules/@types/express-serve-static-core": { + "version": "4.19.8", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.8.tgz", + "integrity": "sha512-02S5fmqeoKzVZCHPZid4b8JH2eM5HzQLZWN2FohQEy/0eXTq8VXZfSN6Pcr3F6N9R/vNrj7cpgbhjie6m/1tCA==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/graceful-fs": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", + "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/http-errors": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", + "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", + "dev": true + }, + "node_modules/@types/http-proxy": { + "version": "1.17.17", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.17.tgz", + "integrity": "sha512-ED6LB+Z1AVylNTu7hdzuBqOgMnvG/ld6wGCG8wFnAzKX5uyW2K3WD52v0gnLCTK/VLpXtKckgWuyScYK6cSPaw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "dev": true + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/jsdom": { + "version": "20.0.1", + "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-20.0.1.tgz", + "integrity": "sha512-d0r18sZPmMQr1eG35u12FZfhIXNrnsPU/g5wvRKCUf/tOGilKKwYMYGqh33BNR6ba+2gkHw1EUiHoN3mn7E5IQ==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/tough-cookie": "*", + "parse5": "^7.0.0" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "dev": true + }, + "node_modules/@types/minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==", + "dev": true + }, + "node_modules/@types/mysql": { + "version": "2.15.26", + "resolved": "https://registry.npmjs.org/@types/mysql/-/mysql-2.15.26.tgz", + "integrity": "sha512-DSLCOXhkvfS5WNNPbfn2KdICAmk8lLc+/PNvnPnF7gOdMZCxopXduqv0OQ13y/yA/zXTSikZZqVgybUxOEg6YQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/node": { + "version": "20.19.41", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.41.tgz", + "integrity": "sha512-ECymXOukMnOoVkC2bb1Vc/w/836DXncOg5m8Xj1RH7xSHZJWNYY6Zh7EH477vcnD5egKNNfy2RpNOmuChhFPgQ==", + "dev": true, + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/node-forge": { + "version": "1.3.14", + "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.14.tgz", + "integrity": "sha512-mhVF2BnD4BO+jtOp7z1CdzaK4mbuK0LLQYAvdOLqHTavxFNq4zA1EmYkpnFjP8HOUzedfQkRnp0E2ulSAYSzAw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/normalize-package-data": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", + "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", + "dev": true + }, + "node_modules/@types/parse-json": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", + "dev": true + }, + "node_modules/@types/pg": { + "version": "8.6.1", + "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.6.1.tgz", + "integrity": "sha512-1Kc4oAGzAl7uqUStZCDvaLFqZrW9qWSjXOmBfdgyBP5La7Us6Mg4GBvRlSoaZMhQF/zSj1C8CtKMBkoiT8eL8w==", + "dev": true, + "dependencies": { + "@types/node": "*", + "pg-protocol": "*", + "pg-types": "^2.2.0" + } + }, + "node_modules/@types/pg-pool": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/pg-pool/-/pg-pool-2.0.6.tgz", + "integrity": "sha512-TaAUE5rq2VQYxab5Ts7WZhKNmuN78Q6PiFonTDdpbx8a1H0M1vhy3rhiMjl+e2iHmogyMw7jZF4FrE6eJUy5HQ==", + "dev": true, + "dependencies": { + "@types/pg": "*" + } + }, + "node_modules/@types/prop-types": { + "version": "15.7.15", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", + "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==" + }, + "node_modules/@types/qs": { + "version": "6.15.1", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.15.1.tgz", + "integrity": "sha512-GZHUBZR9hckSUhrxmp1nG6NwdpM9fCunJwyThLW1X3AyHgd9IlHb6VANpQQqDr2o/qQp6McZ3y/IA2rVzKzSbw==", + "dev": true + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true + }, + "node_modules/@types/react": { + "version": "18.3.29", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.29.tgz", + "integrity": "sha512-ch0qJdr2JY0r04NXSprbK6TXOgnaJ1Tz23fm5W+z0/CBah6BSBc3n96h7K9GOtwh0HrilNWHIBzE1Ko4Dcw/Wg==", + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.3.7", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", + "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", + "peerDependencies": { + "@types/react": "^18.0.0" + } + }, + "node_modules/@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", + "dev": true + }, + "node_modules/@types/semver": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==", + "dev": true + }, + "node_modules/@types/send": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.1.tgz", + "integrity": "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/serve-index": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz", + "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==", + "dev": true, + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.10", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.10.tgz", + "integrity": "sha512-tRs1dB+g8Itk72rlSI2ZrW6vZg0YrLI81iQSTkMmOqnqCaNr/8Ek4VwWcN5vZgCYWbg/JJSGBlUaYGAOP73qBw==", + "dev": true, + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "<1" + } + }, + "node_modules/@types/serve-static/node_modules/@types/send": { + "version": "0.17.6", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.6.tgz", + "integrity": "sha512-Uqt8rPBE8SY0RK8JB1EzVOIZ32uqy8HwdxCnoCOsYrvnswqmFZ/k+9Ikidlk/ImhsdvBsloHbAlewb2IEBV/Og==", + "dev": true, + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/shimmer": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@types/shimmer/-/shimmer-1.2.0.tgz", + "integrity": "sha512-UE7oxhQLLd9gub6JKIAhDq06T0F6FnztwMNRvYgjeQSBeMc1ZG/tA47EwfduvkuQS8apbkM/lpLpWsaCeYsXVg==", + "dev": true + }, + "node_modules/@types/sockjs": { + "version": "0.3.36", + "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz", + "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/stack-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", + "dev": true + }, + "node_modules/@types/tedious": { + "version": "4.0.14", + "resolved": "https://registry.npmjs.org/@types/tedious/-/tedious-4.0.14.tgz", + "integrity": "sha512-KHPsfX/FoVbUGbyYvk1q9MMQHLPeRZhRJZdO45Q4YjvFkv4hMNghCWTvy7rdKessBsmtz4euWCWAB6/tVpI1Iw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/tough-cookie": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz", + "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==", + "dev": true + }, + "node_modules/@types/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/yargs": { + "version": "17.0.35", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.35.tgz", + "integrity": "sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "dev": true + }, + "node_modules/@types/yauzl": { + "version": "2.10.3", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", + "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", + "dev": true, + "optional": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz", + "integrity": "sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/type-utils": "6.21.0", + "@typescript-eslint/utils": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.4", + "natural-compare": "^1.4.0", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz", + "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz", + "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/typescript-estree": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz", + "integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz", + "integrity": "sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "6.21.0", + "@typescript-eslint/utils": "6.21.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz", + "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==", + "dev": true, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz", + "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "9.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz", + "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.21.0.tgz", + "integrity": "sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/typescript-estree": "6.21.0", + "semver": "^7.5.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/semver": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz", + "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz", + "integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.1.tgz", + "integrity": "sha512-mUFwbeTqrVgDQxFveS+df2yfap6iuP20NAKAsBt5jDEoOTDew+zwLAOilHCeQJOVSvmgCX4ogqIrA0mnyr08yQ==", + "dev": true + }, + "node_modules/@unrs/resolver-binding-android-arm-eabi": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.12.2.tgz", + "integrity": "sha512-g5T90pqg1bo/7mytQx6F4iBNC0Wsh9cu+z9veDbFjc7HjpesJFWD7QMS0NGStXM075+7dJPPVvBbpZlnrdpi/w==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@unrs/resolver-binding-android-arm64": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.12.2.tgz", + "integrity": "sha512-YGCRZv/9GLhwmz6mYDeTsm/92BAyR28l6c2ReweVW5pWgfsitWLY8upvfRlGdoyD8HjeTHSYJWyZGD4KJA/nFQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@unrs/resolver-binding-darwin-arm64": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.12.2.tgz", + "integrity": "sha512-u9DiNT1auQMO20A9SyTuG3wUgQWB9Z7KjAg0uFuCDR1FsAY8A0CG2S6JpHS1xwm/w1G08bjXZDcyOCjv1WAm2w==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-darwin-x64": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.12.2.tgz", + "integrity": "sha512-f7rPLi/T1HVKZu/u6t87lroib16n8vrSzcyxI7lg4BGO9UF26KhQL44sd9eOUgrTYhvRXtWOIZT5PejdPyJfUA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-freebsd-x64": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.12.2.tgz", + "integrity": "sha512-BpcOjWCJub6nRZUS2zA20pmLvjtqAtGejETaIyRLiZiQf++cbrjltLA5NN/xaXfqeOBOSlMFbemIl5/S5tljmg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.12.2.tgz", + "integrity": "sha512-vZTDvdSISZjJx66OzJqtsOhzifbqRjbmI1Mnu49fQDwog5GtDI4QidRiEAYbZCRj9C8YZEW+3ZjqsyS9GR4k2A==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-musleabihf": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.12.2.tgz", + "integrity": "sha512-BiPI+IrIlwcW4nLLMM21+B1dFPzd55yAVgVGrdgDjNef+ch03GdxrcyaIz8X9SsQirh/kCQ7mviyWlMxdh2D7g==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-gnu": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.12.2.tgz", + "integrity": "sha512-zJc0H99FEPoFfSrNpa91HYfxzfAJCr502oxNK1cfdC9hlaFI43RT+JFCann9JUgZmLzzntChHyn13Sgn9ljHNg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-musl": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.12.2.tgz", + "integrity": "sha512-KQ3Lki6l+Pz1k/eBipN41ES+YUK30beLGb9YqcB1O542cyLCNE6GaxrfcY3T6EezmGGk84wb5XyO9loTM9tkcA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-loong64-gnu": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-loong64-gnu/-/resolver-binding-linux-loong64-gnu-1.12.2.tgz", + "integrity": "sha512-3SJGEh1DborhG6pyxvhPzCT4bbSIVihsvgJc13P1bHG7KLdNDaF9T3gsTwFc7Jw/5Y5/iWOjkEx7Zy0NvCGX3Q==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-loong64-musl": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-loong64-musl/-/resolver-binding-linux-loong64-musl-1.12.2.tgz", + "integrity": "sha512-jiuG/Obbel7uw1PwHNFfrkiKhLAF6mnyZ6aWlOAVN9WqKm8v0OFGnciJIHu8+CMvXLQ8AD51LPzAoUfT21D5Ew==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-ppc64-gnu": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.12.2.tgz", + "integrity": "sha512-q7xRvVpmcfeL+LlZg8Pbbo6QaTZwDU5BaGZbwfhkEsXJn3Was8xYfE0RBH266xZt0rM6B7i8xAYIvjthuUIWHg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-gnu": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.12.2.tgz", + "integrity": "sha512-0CVdx6lcnT3Q9inOH8tsMIOJ6ImndllMjqJHg8RLVdB7Vq4SfkEXl9mCSsVNuNA4MCYycRicCUxPCabVHJRr6A==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-musl": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.12.2.tgz", + "integrity": "sha512-iOwlRo9vnp6R6ohHQS11n0NnfdXx/omhkocmIfaPRpQhKZ+3BDMkkdRVh53qjkFkpPddf+FETA28NwGN7l5l+w==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-s390x-gnu": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.12.2.tgz", + "integrity": "sha512-HYJtLfXq94q8iZNFT1lknx258wlkkWhZeUXJRqzKBBUJ00CvZ+N33zgbCqimLjsyw5Va6uUxhVa12mI+kaveEw==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-gnu": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.12.2.tgz", + "integrity": "sha512-mPsUhunKKDih5O96Y6enDQyHc1SqBPlY1E/SfMWDM3EdJ95Z9CArPeCVwCCqbP45ljvivdEk8Fxn+SIb1rDAJQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-musl": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.12.2.tgz", + "integrity": "sha512-azrt6+5ydLd8Vt210AAFis/lZevSfPw93EJRIJG+xPu4WCJ8K0kppCTpMyLPcKT7H15M4Jnt2tMp5bOvCkRC6A==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-openharmony-arm64": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-openharmony-arm64/-/resolver-binding-openharmony-arm64-1.12.2.tgz", + "integrity": "sha512-YZ9hP4O0X9PQb8eO980qmLNGH4zT3I9+SZTdt0Pr0YyuGQhYKoOZkV02VzrzyOZJ5xIJ3UFIenKkUkGg8GjgWQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@unrs/resolver-binding-wasm32-wasi": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.12.2.tgz", + "integrity": "sha512-tYFDIkMxSflfEc/h92ZWNsZlHSwgimbNHSO3PL2JWQHfCuC2q316jMyYU9TIWZsFK2bQwyK5VAdYgn8ygPj69A==", + "cpu": [ + "wasm32" + ], + "dev": true, + "optional": true, + "dependencies": { + "@emnapi/core": "1.10.0", + "@emnapi/runtime": "1.10.0", + "@napi-rs/wasm-runtime": "^1.1.4" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@unrs/resolver-binding-win32-arm64-msvc": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.12.2.tgz", + "integrity": "sha512-qzNyg3xL0VPQmCaUh+N5jSitce6k+uCBfMDesWRnlULOZaqUkaJ0ybdT+UqlAWJoQjuqfIU/0Ptx9bteN4D82g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-ia32-msvc": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.12.2.tgz", + "integrity": "sha512-WD9sY00OfpHVGfsnHZoA8jVT+esS/Bg8z8jzxp5BnDCjjwsuKsPQrzswwpFy4J1AUJbXPRfkpcX0mXrzeXW79g==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-x64-msvc": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.12.2.tgz", + "integrity": "sha512-nAB74NfSNKknqQ1RrYj6uz8FcXEomu/MATJZxh/x+BArzN2U3JbOYC0APYzUIGhVY3m5hRxA8VPNdPBoG8txlA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", + "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", + "dev": true, + "dependencies": { + "@webassemblyjs/helper-numbers": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", + "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", + "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", + "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", + "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", + "dev": true, + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.13.2", + "@webassemblyjs/helper-api-error": "1.13.2", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", + "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", + "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/wasm-gen": "1.14.1" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", + "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", + "dev": true, + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", + "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", + "dev": true, + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", + "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", + "dev": true + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", + "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/helper-wasm-section": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-opt": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1", + "@webassemblyjs/wast-printer": "1.14.1" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", + "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", + "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", + "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-api-error": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", + "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webpack-cli/configtest": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.1.1.tgz", + "integrity": "sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + } + }, + "node_modules/@webpack-cli/info": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.2.tgz", + "integrity": "sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + } + }, + "node_modules/@webpack-cli/serve": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.5.tgz", + "integrity": "sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + }, + "peerDependenciesMeta": { + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/@wordpress/api-fetch": { + "version": "7.46.0", + "resolved": "https://registry.npmjs.org/@wordpress/api-fetch/-/api-fetch-7.46.0.tgz", + "integrity": "sha512-QOxuHSUXMzLat3Y90+0HNUDPSlBUK53r4mQ4m7f4/OKaWRRZU5jzvDBJyj52dEST7yJ1eZtuqUkEwK2T1MEBfQ==", + "dependencies": { + "@wordpress/i18n": "^6.19.0", + "@wordpress/url": "^4.46.0" + }, + "engines": { + "node": ">=18.12.0", + "npm": ">=8.19.2" + } + }, + "node_modules/@wordpress/api-fetch/node_modules/@wordpress/i18n": { + "version": "6.19.0", + "resolved": "https://registry.npmjs.org/@wordpress/i18n/-/i18n-6.19.0.tgz", + "integrity": "sha512-hRXd2E0SF9OQf22ZZWw7Ny/o+Q9u8jINiF1p0bF+rnSDKQUgoStihak6YiazWVRiIEYwctzotKXlt0HePJelXA==", + "dependencies": { + "@tannin/sprintf": "^1.3.2", + "@wordpress/hooks": "^4.46.0", + "gettext-parser": "^1.3.1", + "memize": "^2.1.0", + "tannin": "^1.2.0" + }, + "bin": { + "pot-to-php": "tools/pot-to-php.js" + }, + "engines": { + "node": ">=18.12.0", + "npm": ">=8.19.2" + } + }, + "node_modules/@wordpress/babel-preset-default": { + "version": "8.46.0", + "resolved": "https://registry.npmjs.org/@wordpress/babel-preset-default/-/babel-preset-default-8.46.0.tgz", + "integrity": "sha512-HpjX32OkbSpNZkhVo2WdQuP1MkpVg24hVaq7uM5whDdYR88pSc5bfhJ1cNsWagYJQvuYFBf+YIBSvxref4ojXA==", + "dev": true, + "dependencies": { + "@babel/core": "7.25.7", + "@babel/plugin-syntax-import-attributes": "7.26.0", + "@babel/plugin-transform-react-jsx": "7.25.7", + "@babel/plugin-transform-runtime": "7.25.7", + "@babel/preset-env": "7.25.7", + "@babel/preset-typescript": "7.25.7", + "@wordpress/browserslist-config": "^6.46.0", + "@wordpress/warning": "^3.46.0", + "browserslist": "^4.21.10", + "core-js": "^3.31.0", + "react": "^18.3.0" + }, + "engines": { + "node": ">=18.12.0", + "npm": ">=8.19.2" + } + }, + "node_modules/@wordpress/babel-preset-default/node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.26.0.tgz", + "integrity": "sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@wordpress/babel-preset-default/node_modules/@babel/plugin-transform-react-jsx": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.25.7.tgz", + "integrity": "sha512-vILAg5nwGlR9EXE8JIOX4NHXd49lrYbN8hnjffDtoULwpL9hUx/N55nqh2qd0q6FyNDfjl9V79ecKGvFbcSA0Q==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.7", + "@babel/helper-module-imports": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/plugin-syntax-jsx": "^7.25.7", + "@babel/types": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@wordpress/babel-preset-default/node_modules/@babel/preset-env": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.25.7.tgz", + "integrity": "sha512-Gibz4OUdyNqqLj+7OAvBZxOD7CklCtMA5/j0JgUEwOnaRULsPDXmic2iKxL2DX2vQduPR5wH2hjZas/Vr/Oc0g==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.25.7", + "@babel/helper-compilation-targets": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/helper-validator-option": "^7.25.7", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.25.7", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.25.7", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.25.7", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.25.7", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.25.7", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-import-assertions": "^7.25.7", + "@babel/plugin-syntax-import-attributes": "^7.25.7", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.25.7", + "@babel/plugin-transform-async-generator-functions": "^7.25.7", + "@babel/plugin-transform-async-to-generator": "^7.25.7", + "@babel/plugin-transform-block-scoped-functions": "^7.25.7", + "@babel/plugin-transform-block-scoping": "^7.25.7", + "@babel/plugin-transform-class-properties": "^7.25.7", + "@babel/plugin-transform-class-static-block": "^7.25.7", + "@babel/plugin-transform-classes": "^7.25.7", + "@babel/plugin-transform-computed-properties": "^7.25.7", + "@babel/plugin-transform-destructuring": "^7.25.7", + "@babel/plugin-transform-dotall-regex": "^7.25.7", + "@babel/plugin-transform-duplicate-keys": "^7.25.7", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.25.7", + "@babel/plugin-transform-dynamic-import": "^7.25.7", + "@babel/plugin-transform-exponentiation-operator": "^7.25.7", + "@babel/plugin-transform-export-namespace-from": "^7.25.7", + "@babel/plugin-transform-for-of": "^7.25.7", + "@babel/plugin-transform-function-name": "^7.25.7", + "@babel/plugin-transform-json-strings": "^7.25.7", + "@babel/plugin-transform-literals": "^7.25.7", + "@babel/plugin-transform-logical-assignment-operators": "^7.25.7", + "@babel/plugin-transform-member-expression-literals": "^7.25.7", + "@babel/plugin-transform-modules-amd": "^7.25.7", + "@babel/plugin-transform-modules-commonjs": "^7.25.7", + "@babel/plugin-transform-modules-systemjs": "^7.25.7", + "@babel/plugin-transform-modules-umd": "^7.25.7", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.25.7", + "@babel/plugin-transform-new-target": "^7.25.7", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.25.7", + "@babel/plugin-transform-numeric-separator": "^7.25.7", + "@babel/plugin-transform-object-rest-spread": "^7.25.7", + "@babel/plugin-transform-object-super": "^7.25.7", + "@babel/plugin-transform-optional-catch-binding": "^7.25.7", + "@babel/plugin-transform-optional-chaining": "^7.25.7", + "@babel/plugin-transform-parameters": "^7.25.7", + "@babel/plugin-transform-private-methods": "^7.25.7", + "@babel/plugin-transform-private-property-in-object": "^7.25.7", + "@babel/plugin-transform-property-literals": "^7.25.7", + "@babel/plugin-transform-regenerator": "^7.25.7", + "@babel/plugin-transform-reserved-words": "^7.25.7", + "@babel/plugin-transform-shorthand-properties": "^7.25.7", + "@babel/plugin-transform-spread": "^7.25.7", + "@babel/plugin-transform-sticky-regex": "^7.25.7", + "@babel/plugin-transform-template-literals": "^7.25.7", + "@babel/plugin-transform-typeof-symbol": "^7.25.7", + "@babel/plugin-transform-unicode-escapes": "^7.25.7", + "@babel/plugin-transform-unicode-property-regex": "^7.25.7", + "@babel/plugin-transform-unicode-regex": "^7.25.7", + "@babel/plugin-transform-unicode-sets-regex": "^7.25.7", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.10", + "babel-plugin-polyfill-corejs3": "^0.10.6", + "babel-plugin-polyfill-regenerator": "^0.6.1", + "core-js-compat": "^3.38.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@wordpress/babel-preset-default/node_modules/@babel/preset-env/node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@wordpress/babel-preset-default/node_modules/@babel/preset-env/node_modules/@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@wordpress/babel-preset-default/node_modules/@babel/preset-env/node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.10.6", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.6.tgz", + "integrity": "sha512-b37+KR2i/khY5sKmWNVQAnitvquQbNdWy6lJdsr0kmquCKEEUgMKK4SboVM3HtfnZilfjr4MMQ7vY58FVWDtIA==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.2", + "core-js-compat": "^3.38.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@wordpress/babel-preset-default/node_modules/@babel/preset-typescript": { + "version": "7.25.7", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.25.7.tgz", + "integrity": "sha512-rkkpaXJZOFN45Fb+Gki0c+KMIglk4+zZXOoMJuyEK8y8Kkc8Jd3BDmP7qPsz0zQMJj+UD7EprF+AqAXcILnexw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.25.7", + "@babel/helper-validator-option": "^7.25.7", + "@babel/plugin-syntax-jsx": "^7.25.7", + "@babel/plugin-transform-modules-commonjs": "^7.25.7", + "@babel/plugin-transform-typescript": "^7.25.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@wordpress/base-styles": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@wordpress/base-styles/-/base-styles-8.0.0.tgz", + "integrity": "sha512-livtgwnvBm7xbpm/gaBxwtdZm3KCXq210UNsr48WA8TGfi/OfZ4oOzk4Mp4/ZHsq2baaXzhZ0iXjyR7oyaOTsw==", + "dev": true, + "engines": { + "node": ">=18.12.0", + "npm": ">=8.19.2" + } + }, + "node_modules/@wordpress/browserslist-config": { + "version": "6.46.0", + "resolved": "https://registry.npmjs.org/@wordpress/browserslist-config/-/browserslist-config-6.46.0.tgz", + "integrity": "sha512-FV/CN/Qjvu0Ts1h63w0xuZyhKzipyePMFGXPmbZawu+fHpib/2D/JyAHb0wVpOD4qz8XOfB8Tyi9iMPJzAI87w==", + "dev": true, + "engines": { + "node": ">=18.12.0", + "npm": ">=8.19.2" + } + }, + "node_modules/@wordpress/dependency-extraction-webpack-plugin": { + "version": "6.46.0", + "resolved": "https://registry.npmjs.org/@wordpress/dependency-extraction-webpack-plugin/-/dependency-extraction-webpack-plugin-6.46.0.tgz", + "integrity": "sha512-Lm2JFEI4NrcEQFdnIXK+CsUQGK/LTiRxrDY0ocpTLt5hhb3DJm3Ds2HFn8fa//H0U5B3FvO3XyGMHOUf9Q12Pg==", + "dev": true, + "dependencies": { + "json2php": "^0.0.7" + }, + "engines": { + "node": ">=18.12.0", + "npm": ">=8.19.2" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/@wordpress/dependency-extraction-webpack-plugin/node_modules/json2php": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/json2php/-/json2php-0.0.7.tgz", + "integrity": "sha512-dnSoUiLAoVaMXxFsVi4CrPVYMKOuDBXTghXSmMINX44RZ8WM9cXlY7UqrQnlAcODCVO7FV3+8t/5nDKAjimLfg==", + "dev": true + }, + "node_modules/@wordpress/e2e-test-utils-playwright": { + "version": "1.46.0", + "resolved": "https://registry.npmjs.org/@wordpress/e2e-test-utils-playwright/-/e2e-test-utils-playwright-1.46.0.tgz", + "integrity": "sha512-Bls5BGRNda0Oo4biTZ/KIwO8iHBeovvfWNfrPXReIsrW1td1UqXw2Z9l0/LaP3euJZFNom2QExHCOba+8eN5lQ==", + "dev": true, + "dependencies": { + "change-case": "^4.1.2", + "get-port": "^5.1.1", + "lighthouse": "^12.2.2", + "mime": "^3.0.0", + "web-vitals": "^4.2.1" + }, + "engines": { + "node": ">=18.12.0", + "npm": ">=8.19.2" + }, + "peerDependencies": { + "@playwright/test": ">=1", + "@types/node": "^20.17.10" + } + }, + "node_modules/@wordpress/element": { + "version": "6.46.0", + "resolved": "https://registry.npmjs.org/@wordpress/element/-/element-6.46.0.tgz", + "integrity": "sha512-hjnrqZi0cZVdkmN0xQavKfSQJYAkb9pVSnDPpuX65OLxeD9/EWkIXvFzBb+nH8c4NzKKSqQU96XCTQrH37OCIA==", + "dependencies": { + "@types/react": "^18.3.27", + "@types/react-dom": "^18.3.1", + "@wordpress/escape-html": "^3.46.0", + "change-case": "^4.1.2", + "is-plain-object": "^5.0.0", + "react": "^18.3.0", + "react-dom": "^18.3.0" + }, + "engines": { + "node": ">=18.12.0", + "npm": ">=8.19.2" + } + }, + "node_modules/@wordpress/escape-html": { + "version": "3.46.0", + "resolved": "https://registry.npmjs.org/@wordpress/escape-html/-/escape-html-3.46.0.tgz", + "integrity": "sha512-SzrVQwLQBZdaSStYVpTKeYqp97NABz1w551T8me3msDDsfhWWPhSZiZTNaGZ6iqUNfOX2uKyZsqXedvkqwLHqA==", + "engines": { + "node": ">=18.12.0", + "npm": ">=8.19.2" + } + }, + "node_modules/@wordpress/eslint-plugin": { + "version": "22.22.0", + "resolved": "https://registry.npmjs.org/@wordpress/eslint-plugin/-/eslint-plugin-22.22.0.tgz", + "integrity": "sha512-DLGm5i8Gn0vjkZGKF49U2pYME5Jl9AvmoMJB2G508d+sB/oTSkPmM0baUP7G5zxbd1aqfNTaD0KjdyGyWFFKOA==", + "dev": true, + "dependencies": { + "@babel/eslint-parser": "7.25.7", + "@typescript-eslint/eslint-plugin": "^6.4.1", + "@typescript-eslint/parser": "^6.4.1", + "@wordpress/babel-preset-default": "^8.36.0", + "@wordpress/prettier-config": "^4.36.0", + "cosmiconfig": "^7.0.0", + "eslint-config-prettier": "^8.3.0", + "eslint-import-resolver-typescript": "^4.4.4", + "eslint-plugin-import": "^2.25.2", + "eslint-plugin-jest": "^27.4.3", + "eslint-plugin-jsdoc": "^46.4.6", + "eslint-plugin-jsx-a11y": "^6.5.1", + "eslint-plugin-playwright": "^0.15.3", + "eslint-plugin-prettier": "^5.0.0", + "eslint-plugin-react": "^7.27.0", + "eslint-plugin-react-hooks": "^4.3.0", + "globals": "^13.12.0", + "requireindex": "^1.2.0" + }, + "engines": { + "node": ">=18.12.0", + "npm": ">=8.19.2" + }, + "peerDependencies": { + "@babel/core": ">=7", + "eslint": ">=8", + "prettier": ">=3", + "typescript": ">=5" + }, + "peerDependenciesMeta": { + "prettier": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/@wordpress/eslint-plugin/node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "dev": true, + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@wordpress/hooks": { + "version": "4.46.0", + "resolved": "https://registry.npmjs.org/@wordpress/hooks/-/hooks-4.46.0.tgz", + "integrity": "sha512-fsKw4dmw4voIRoKc8t0XRREQlFvwj9XS/jTXvkh6mqRYCDpaEnrdB2Ji5jgbRXEMPU0GKVGMeAn5Wwi56gjBMg==", + "engines": { + "node": ">=18.12.0", + "npm": ">=8.19.2" + } + }, + "node_modules/@wordpress/i18n": { + "version": "5.26.0", + "resolved": "https://registry.npmjs.org/@wordpress/i18n/-/i18n-5.26.0.tgz", + "integrity": "sha512-YHzaUWlCuN2ynl47qbsdMkTGtP52+E1giDOdWBgUaSexUYjbeFxKFUzRMB0Wuh1psL80+VzvJOH/mU440KAJnA==", + "dependencies": { + "@babel/runtime": "7.25.7", + "@wordpress/hooks": "^4.26.0", + "gettext-parser": "^1.3.1", + "memize": "^2.1.0", + "sprintf-js": "^1.1.1", + "tannin": "^1.2.0" + }, + "bin": { + "pot-to-php": "tools/pot-to-php.js" + }, + "engines": { + "node": ">=18.12.0", + "npm": ">=8.19.2" + } + }, + "node_modules/@wordpress/jest-console": { + "version": "8.46.0", + "resolved": "https://registry.npmjs.org/@wordpress/jest-console/-/jest-console-8.46.0.tgz", + "integrity": "sha512-bD5FD/LDbDyfadZzxfUCOM6uBXlIfRFj+AAsgmCHuUBW3c7PrsZXDGh5KRaR8E0XLoeLpkxA78fpUaY8S1+XPw==", + "dev": true, + "dependencies": { + "jest-matcher-utils": "^29.6.2", + "jest-mock": "^29.6.2" + }, + "engines": { + "node": ">=18.12.0", + "npm": ">=8.19.2" + }, + "peerDependencies": { + "jest": ">=29" + } + }, + "node_modules/@wordpress/jest-preset-default": { + "version": "12.46.0", + "resolved": "https://registry.npmjs.org/@wordpress/jest-preset-default/-/jest-preset-default-12.46.0.tgz", + "integrity": "sha512-R6D1IMFD1lkpTg8MI5g0c5Bb2TFwp37ZIHR5Xsv7cfK4e73Xk/NsQ5ImP0MyPNIu90IYMcGDOgCdUll7fgeLZg==", + "dev": true, + "dependencies": { + "@wordpress/jest-console": "^8.46.0", + "babel-jest": "29.7.0" + }, + "engines": { + "node": ">=18.12.0", + "npm": ">=8.19.2" + }, + "peerDependencies": { + "@babel/core": ">=7", + "jest": ">=29" + } + }, + "node_modules/@wordpress/npm-package-json-lint-config": { + "version": "5.46.0", + "resolved": "https://registry.npmjs.org/@wordpress/npm-package-json-lint-config/-/npm-package-json-lint-config-5.46.0.tgz", + "integrity": "sha512-8LoW3tNXA1cjehpP/12g20HnbYAQ7n7//D6f3cha4Ev295XXGszxI2FSzk7OLEgV1QtQgCyijEC196RABRCilQ==", + "dev": true, + "engines": { + "node": ">=18.12.0", + "npm": ">=8.19.2" + }, + "peerDependencies": { + "npm-package-json-lint": ">=6.0.0" + } + }, + "node_modules/@wordpress/postcss-plugins-preset": { + "version": "5.46.0", + "resolved": "https://registry.npmjs.org/@wordpress/postcss-plugins-preset/-/postcss-plugins-preset-5.46.0.tgz", + "integrity": "sha512-0cQq8mHFKqDCunu84oekhw/E2bE1paOxKPGAxe8mXdCAYrW/ZyIlHlNLBAy/EfI621UMsQYAz95KrJoKA9h0YA==", + "dev": true, + "dependencies": { + "@wordpress/base-styles": "^8.0.0", + "autoprefixer": "^10.4.20", + "postcss-import": "^16.1.1" + }, + "engines": { + "node": ">=18.12.0", + "npm": ">=8.19.2" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/@wordpress/prettier-config": { + "version": "4.46.0", + "resolved": "https://registry.npmjs.org/@wordpress/prettier-config/-/prettier-config-4.46.0.tgz", + "integrity": "sha512-KjqvxbBohc0dtZBCYy82chj9WCa5nSQP7LuXrsTo5xFacRrNaB101TlsogVoaHADbOlcrayC0yRPzVmkA8gJFg==", + "dev": true, + "engines": { + "node": ">=18.12.0", + "npm": ">=8.19.2" + }, + "peerDependencies": { + "prettier": ">=3" + } + }, + "node_modules/@wordpress/private-apis": { + "version": "1.46.0", + "resolved": "https://registry.npmjs.org/@wordpress/private-apis/-/private-apis-1.46.0.tgz", + "integrity": "sha512-l8dsEuxq6CrtsI7Twfpn6CbPHmGBUQoGN4oLPJG1Bqsr1yXXLU/bEx9KAQN9emxRjXaELPsn7x7TVx0TUoKyJw==", + "dev": true, + "engines": { + "node": ">=18.12.0", + "npm": ">=8.19.2" + } + }, + "node_modules/@wordpress/scripts": { + "version": "30.27.0", + "resolved": "https://registry.npmjs.org/@wordpress/scripts/-/scripts-30.27.0.tgz", + "integrity": "sha512-gXGptazCxAaR7g8kcN5joj7B5fCm0VeBHOmnDBs2dbQ4W4F3tfzdg6CTEj8LonF9bWQXlSy3ku8EqWCdkSG9Xw==", + "dev": true, + "dependencies": { + "@babel/core": "7.25.7", + "@pmmmwh/react-refresh-webpack-plugin": "^0.5.11", + "@svgr/webpack": "^8.0.1", + "@wordpress/babel-preset-default": "^8.34.0", + "@wordpress/browserslist-config": "^6.34.0", + "@wordpress/dependency-extraction-webpack-plugin": "^6.34.0", + "@wordpress/e2e-test-utils-playwright": "^1.34.0", + "@wordpress/eslint-plugin": "^22.20.0", + "@wordpress/jest-preset-default": "^12.34.0", + "@wordpress/npm-package-json-lint-config": "^5.34.0", + "@wordpress/postcss-plugins-preset": "^5.34.0", + "@wordpress/prettier-config": "^4.34.0", + "@wordpress/stylelint-config": "^23.26.0", + "adm-zip": "^0.5.9", + "babel-jest": "29.7.0", + "babel-loader": "9.2.1", + "browserslist": "^4.21.10", + "chalk": "^4.0.0", + "check-node-version": "^4.1.0", + "copy-webpack-plugin": "^10.2.0", + "cross-spawn": "^7.0.6", + "css-loader": "^6.2.0", + "cssnano": "^6.0.1", + "cwd": "^0.10.0", + "dir-glob": "^3.0.1", + "eslint": "^8.3.0", + "expect-puppeteer": "^4.4.0", + "fast-glob": "^3.2.7", + "filenamify": "^4.2.0", + "jest": "^29.6.2", + "jest-dev-server": "^10.1.4", + "jest-environment-jsdom": "^29.6.2", + "jest-environment-node": "^29.6.2", + "json2php": "^0.0.9", + "markdownlint-cli": "^0.31.1", + "merge-deep": "^3.0.3", + "mini-css-extract-plugin": "^2.9.2", + "minimist": "^1.2.0", + "npm-package-json-lint": "^6.4.0", + "npm-packlist": "^3.0.0", + "postcss": "^8.4.5", + "postcss-loader": "^6.2.1", + "prettier": "npm:wp-prettier@3.0.3", + "puppeteer-core": "^23.10.1", + "react-refresh": "^0.14.0", + "read-pkg-up": "^7.0.1", + "resolve-bin": "^0.4.0", + "rtlcss": "^4.3.0", + "sass": "^1.54.0", + "sass-loader": "^16.0.3", + "schema-utils": "^4.2.0", + "source-map-loader": "^3.0.0", + "stylelint": "^16.8.2", + "terser-webpack-plugin": "^5.3.10", + "url-loader": "^4.1.1", + "webpack": "^5.97.0", + "webpack-bundle-analyzer": "^4.9.1", + "webpack-cli": "^5.1.4", + "webpack-dev-server": "^4.15.1" + }, + "bin": { + "wp-scripts": "bin/wp-scripts.js" + }, + "engines": { + "node": ">=18.12.0", + "npm": ">=8.19.2" + }, + "peerDependencies": { + "@playwright/test": "^1.56.1", + "@wordpress/env": "^10.0.0", + "react": "^18.0.0", + "react-dom": "^18.0.0" + }, + "peerDependenciesMeta": { + "@wordpress/env": { + "optional": true + } + } + }, + "node_modules/@wordpress/style-runtime": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@wordpress/style-runtime/-/style-runtime-0.2.0.tgz", + "integrity": "sha512-9pLmilkgWqTvIlrnnXbW7ECfEPvCSYOve7btXgYGgMOzrGs12ijnG+kSGGg0aJhEV8OCzQ/QdVBh4s1zQZ0bLQ==", + "dev": true, + "engines": { + "node": ">=20.10.0", + "npm": ">=10.2.3" + } + }, + "node_modules/@wordpress/stylelint-config": { + "version": "23.38.0", + "resolved": "https://registry.npmjs.org/@wordpress/stylelint-config/-/stylelint-config-23.38.0.tgz", + "integrity": "sha512-F1Bo45fhWFrpEXlkkwVfopmmgM8PwbzplrlBwu1FGm+9ohF890IXKhjjQ/CDphE9pMBCQnAyofF6ESymhbEm5A==", + "dev": true, + "dependencies": { + "@stylistic/stylelint-plugin": "^3.0.1", + "@wordpress/theme": "^0.13.0", + "stylelint-config-recommended": "^14.0.1", + "stylelint-config-recommended-scss": "^14.1.0" + }, + "engines": { + "node": ">=18.12.0", + "npm": ">=8.19.2" + }, + "peerDependencies": { + "stylelint": "^16.8.2", + "stylelint-scss": "^6.4.0" + } + }, + "node_modules/@wordpress/theme": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@wordpress/theme/-/theme-0.13.0.tgz", + "integrity": "sha512-4Lasso3BPej43c7e+eO+YN/fl/mcg/Q9+nclp1FmV6xdWFiUXvfwAOsEeNQQ/5s5mw5aCgseK3//qX5gydhfUA==", + "dev": true, + "dependencies": { + "@wordpress/element": "^6.46.0", + "@wordpress/private-apis": "^1.46.0", + "@wordpress/style-runtime": "^0.2.0", + "colorjs.io": "^0.6.0", + "memize": "^2.1.0" + }, + "engines": { + "node": ">=18.12.0", + "npm": ">=8.19.2" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": "^18.0.0", + "stylelint": "^16.8.2" + }, + "peerDependenciesMeta": { + "stylelint": { + "optional": true + } + } + }, + "node_modules/@wordpress/url": { + "version": "4.46.0", + "resolved": "https://registry.npmjs.org/@wordpress/url/-/url-4.46.0.tgz", + "integrity": "sha512-LGja+dYBzaNkkPSE5ddPgk03M66wadUheuhyOLTu4uLQU2UmipN9qQgI4VAnZLrnXs7dqb4fJ8f0AuNmshHpbg==", + "dependencies": { + "remove-accents": "^0.5.0" + }, + "engines": { + "node": ">=18.12.0", + "npm": ">=8.19.2" + } + }, + "node_modules/@wordpress/warning": { + "version": "3.46.0", + "resolved": "https://registry.npmjs.org/@wordpress/warning/-/warning-3.46.0.tgz", + "integrity": "sha512-Z1CE6x732iMD+NcWziitqWUyhxVy1JlioHDtQUU2oqhDcA0d/P2ifOc/af02dDYFIuLh7umurU19LqpBX6EoWw==", + "dev": true, + "engines": { + "node": ">=18.12.0", + "npm": ">=8.19.2" + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "node_modules/abab": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", + "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", + "deprecated": "Use your platform's native atob() and btoa() methods instead", + "dev": true + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dev": true, + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-globals": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-7.0.1.tgz", + "integrity": "sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q==", + "dev": true, + "dependencies": { + "acorn": "^8.1.0", + "acorn-walk": "^8.0.2" + } + }, + "node_modules/acorn-import-attributes": { + "version": "1.9.5", + "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", + "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", + "dev": true, + "peerDependencies": { + "acorn": "^8" + } + }, + "node_modules/acorn-import-phases": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz", + "integrity": "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==", + "dev": true, + "engines": { + "node": ">=10.13.0" + }, + "peerDependencies": { + "acorn": "^8.14.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.5", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.5.tgz", + "integrity": "sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==", + "dev": true, + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/adm-zip": { + "version": "0.5.17", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.17.tgz", + "integrity": "sha512-+Ut8d9LLqwEvHHJl1+PIHqoyDxFgVN847JTVM3Izi3xHDWPE4UtzzXysMZQs64DMcrJfBeS/uoEP4AD3HQHnQQ==", + "dev": true, + "engines": { + "node": ">=12.0" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/ajv": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-errors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz", + "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==", + "dev": true, + "peerDependencies": { + "ajv": ">=5.0.0" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-formats/node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-html": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.9.tgz", + "integrity": "sha512-ozbS3LuenHVxNRh/wdnN16QapUHzauqSomAl1jwwJRRsGwFwtj644lIhxfWu0Fy0acCij2+AEgHvjscq3dlVXg==", + "dev": true, + "engines": [ + "node >= 0.8.0" + ], + "bin": { + "ansi-html": "bin/ansi-html" + } + }, + "node_modules/ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", + "dev": true, + "engines": [ + "node >= 0.8.0" + ], + "bin": { + "ansi-html": "bin/ansi-html" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/are-docs-informative": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/are-docs-informative/-/are-docs-informative-0.0.2.tgz", + "integrity": "sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==", + "dev": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/argparse/node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "node_modules/aria-query": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", + "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", + "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", + "dev": true, + "dependencies": { + "call-bound": "^1.0.3", + "is-array-buffer": "^3.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "dev": true + }, + "node_modules/array-includes": { + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.9.tgz", + "integrity": "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.24.0", + "es-object-atoms": "^1.1.1", + "get-intrinsic": "^1.3.0", + "is-string": "^1.1.1", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/array.prototype.findlast": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", + "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.findlastindex": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.6.tgz", + "integrity": "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-shim-unscopables": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz", + "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz", + "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.tosorted": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", + "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3", + "es-errors": "^1.3.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", + "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ast-types": { + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", + "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==", + "dev": true, + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/ast-types-flow": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz", + "integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==", + "dev": true + }, + "node_modules/astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/async-function": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", + "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true + }, + "node_modules/atomically": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/atomically/-/atomically-2.1.1.tgz", + "integrity": "sha512-P4w9o2dqARji6P7MHprklbfiArZAWvo07yW7qs3pdljb3BWr12FIB7W+p0zJiuiVsUpRO0iZn1kFFcpPegg0tQ==", + "dev": true, + "dependencies": { + "stubborn-fs": "^2.0.0", + "when-exit": "^2.1.4" + } + }, + "node_modules/autoprefixer": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.5.0.tgz", + "integrity": "sha512-FMhOoZV4+qR6aTUALKX2rEqGG+oyATvwBt9IIzVR5rMa2HRWPkxf+P+PAJLD1I/H5/II+HuZcBJYEFBpq39ong==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "browserslist": "^4.28.2", + "caniuse-lite": "^1.0.30001787", + "fraction.js": "^5.3.4", + "picocolors": "^1.1.1", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/axe-core": { + "version": "4.11.4", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.11.4.tgz", + "integrity": "sha512-KunSNx+TVpkAw/6ULfhnx+HWRecjqZGTOyquAoWHYLRSdK1tB5Ihce1ZW+UY3fj33bYAFWPu7W/GRSmmrCGuxA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/axios": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.16.1.tgz", + "integrity": "sha512-caYkukvroVPO8KrzuJEb50Hm07KwfBZPEC3VeFHTsqWHvKTsy54hjJz9BS/cdaypROE2rH6xvm9mHX4fgWkr3A==", + "dev": true, + "dependencies": { + "follow-redirects": "^1.16.0", + "form-data": "^4.0.5", + "https-proxy-agent": "^5.0.1", + "proxy-from-env": "^2.1.0" + } + }, + "node_modules/axios/node_modules/proxy-from-env": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", + "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/axobject-query": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", + "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/babel-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", + "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", + "dev": true, + "dependencies": { + "@jest/transform": "^29.7.0", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^29.6.3", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" + } + }, + "node_modules/babel-loader": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.2.1.tgz", + "integrity": "sha512-fqe8naHt46e0yIdkjUZYqddSXfej3AHajX+CSO5X7oy0EmPc6o5Xh+RClNoHjnieWz9AW4kZxW9yyFMhVB1QLA==", + "dev": true, + "dependencies": { + "find-cache-dir": "^4.0.0", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0", + "webpack": ">=5" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", + "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", + "dev": true, + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.17", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.17.tgz", + "integrity": "sha512-aTyf30K/rqAsNwN76zYrdtx8obu0E4KoUME29B1xj+B3WxgvWkp943vYQ+z8Mv3lw9xHXMHpvSPOBxzAkIa94w==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.28.6", + "@babel/helper-define-polyfill-provider": "^0.6.8", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.14.2.tgz", + "integrity": "sha512-coWpDLJ410R781Npmn/SIBZEsAetR4xVi0SxLMXPaMO4lSf1MwnkGYMtkFxew0Dn8B3/CpbpYxN0JCgg8mn67g==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.8", + "core-js-compat": "^3.48.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.8.tgz", + "integrity": "sha512-M762rNHfSF1EV3SLtnCJXFoQbbIIz0OyRwnCmV0KPC7qosSfCO0QLTSuJX3ayAebubhE6oYBAYPrBA5ljowaZg==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.8" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz", + "integrity": "sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==", + "dev": true, + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-import-attributes": "^7.24.7", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5" + }, + "peerDependencies": { + "@babel/core": "^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/babel-preset-jest": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", + "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", + "dev": true, + "dependencies": { + "babel-plugin-jest-hoist": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/bare-events": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.8.3.tgz", + "integrity": "sha512-HdUm8EMQBLaJvGUdidNNbqpA1kYkwNcb+MYxkxCLAPJGQzlv9J0C24h8V65Z4c5GLd/JEALDvpFCQgpLJqc0zw==", + "dev": true, + "peerDependencies": { + "bare-abort-controller": "*" + }, + "peerDependenciesMeta": { + "bare-abort-controller": { + "optional": true + } + } + }, + "node_modules/bare-fs": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.7.1.tgz", + "integrity": "sha512-WDRsyVN52eAx/lBamKD6uyw8H4228h/x0sGGGegOamM2cd7Pag88GfMQalobXI+HaEUxpCkbKQUDOQqt9wawRw==", + "dev": true, + "dependencies": { + "bare-events": "^2.5.4", + "bare-path": "^3.0.0", + "bare-stream": "^2.6.4", + "bare-url": "^2.2.2", + "fast-fifo": "^1.3.2" + }, + "engines": { + "bare": ">=1.16.0" + }, + "peerDependencies": { + "bare-buffer": "*" + }, + "peerDependenciesMeta": { + "bare-buffer": { + "optional": true + } + } + }, + "node_modules/bare-os": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.9.1.tgz", + "integrity": "sha512-6M5XjcnsygQNPMCMPXSK379xrJFiZ/AEMNBmFEmQW8d/789VQATvriyi5r0HYTL9TkQ26rn3kgdTG3aisbrXkQ==", + "dev": true, + "engines": { + "bare": ">=1.14.0" + } + }, + "node_modules/bare-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-3.0.0.tgz", + "integrity": "sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==", + "dev": true, + "dependencies": { + "bare-os": "^3.0.1" + } + }, + "node_modules/bare-stream": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.13.1.tgz", + "integrity": "sha512-Vp0cnjYyrEC4whYTymQ+YZi6pBpfiICZO3cfRG8sy67ZNWe951urv1x4eW1BKNngw3U+3fPYb5JQvHbCtxH7Ow==", + "dev": true, + "dependencies": { + "streamx": "^2.25.0", + "teex": "^1.0.1" + }, + "peerDependencies": { + "bare-abort-controller": "*", + "bare-buffer": "*", + "bare-events": "*" + }, + "peerDependenciesMeta": { + "bare-abort-controller": { + "optional": true + }, + "bare-buffer": { + "optional": true + }, + "bare-events": { + "optional": true + } + } + }, + "node_modules/bare-url": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.4.3.tgz", + "integrity": "sha512-Kccpc7ACfXaxfeInfqKcZtW4pT5YBn1mesc4sCsun6sRwtbJ4h+sNOaksUpYEJUKfN65YWC6Bw2OJEFiKxq8nQ==", + "dev": true, + "dependencies": { + "bare-path": "^3.0.0" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.32", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.32.tgz", + "integrity": "sha512-wbPvpyjJPC0zdfdKXxqEL3Ea+bOMD/87X4lftiJkkaBiuG6ALQy1SLmEd7BSmVCuwCQsBrCamgBoLyfFDD1EPg==", + "dev": true, + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/basic-ftp": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.3.1.tgz", + "integrity": "sha512-bopVNp6ugyA150DDuZfPFdt1KZ5a94ZDiwX4hMgZDzF+GttD80lEy8kj98kbyhLXnPvhtIo93mdnLIjpCAeeOw==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", + "dev": true + }, + "node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/body-parser": { + "version": "1.20.5", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.5.tgz", + "integrity": "sha512-3grm+/2tUOvu2cjJkvsIxrv/wVpfXQW4PsQHYm7yk4vfpu7Ekl6nEsYBoJUL6qDwZUx8wUhQ8tR2qz+ad9c9OA==", + "dev": true, + "dependencies": { + "bytes": "~3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "~1.2.0", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "on-finished": "~2.4.1", + "qs": "~6.15.1", + "raw-body": "~2.5.3", + "type-is": "~1.6.18", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/bonjour-service": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.4.0.tgz", + "integrity": "sha512-fGQtj1qdR9vIKjFiWPQd52qIqwjaYqhcI40JEiDuvlZ86E7ZBPBwY9fPgHy9r2rYGIjiRfctNPYz6OQU73ww2w==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.5" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", + "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.28.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", + "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "baseline-browser-mapping": "^2.10.12", + "caniuse-lite": "^1.0.30001782", + "electron-to-chromium": "^1.5.328", + "node-releases": "^2.0.36", + "update-browserslist-db": "^1.2.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/builtin-modules": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", + "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cacheable": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/cacheable/-/cacheable-2.3.5.tgz", + "integrity": "sha512-EQfaKe09tl615iNvq/TBRWTFf1AKJNXYQSsMx0Z3EI0nA+pVsVPS8wJhnRlkbdacKPh1d0qVIhwTc2zsQNFEEg==", + "dev": true, + "dependencies": { + "@cacheable/memory": "^2.0.8", + "@cacheable/utils": "^2.4.1", + "hookified": "^1.15.0", + "keyv": "^5.6.0", + "qified": "^0.10.1" + } + }, + "node_modules/cacheable/node_modules/keyv": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-5.6.0.tgz", + "integrity": "sha512-CYDD3SOtsHtyXeEORYRx2qBtpDJFjRTGXUtmNEMGyzYOKj1TE3tycdlho7kA1Ufx9OYWZzg52QFBGALTirzDSw==", + "dev": true, + "dependencies": { + "@keyv/serialize": "^1.1.1" + } + }, + "node_modules/call-bind": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.9.tgz", + "integrity": "sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==", + "dev": true, + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "get-intrinsic": "^1.3.0", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "dependencies": { + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/camelcase-keys": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", + "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", + "dev": true, + "dependencies": { + "camelcase": "^5.3.1", + "map-obj": "^4.0.0", + "quick-lru": "^4.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/camelcase-keys/node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-api": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", + "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", + "dev": true, + "dependencies": { + "browserslist": "^4.0.0", + "caniuse-lite": "^1.0.0", + "lodash.memoize": "^4.1.2", + "lodash.uniq": "^4.5.0" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001793", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001793.tgz", + "integrity": "sha512-iwSsYWaCOoh26cV8NwNRViHlrfUvYsHDfRVcbtmw0Kg6PJIZZXwMkj1442FYLBGkeUf1juAsU3DTfxW579mrPA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/capital-case": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/capital-case/-/capital-case-1.0.4.tgz", + "integrity": "sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A==", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3", + "upper-case-first": "^2.0.2" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/change-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/change-case/-/change-case-4.1.2.tgz", + "integrity": "sha512-bSxY2ws9OtviILG1EiY5K7NNxkqg/JnRnFxLtKQ96JaviiIxi7djMrSd0ECT9AC+lttClmYwKw53BWpOMblo7A==", + "dependencies": { + "camel-case": "^4.1.2", + "capital-case": "^1.0.4", + "constant-case": "^3.0.4", + "dot-case": "^3.0.4", + "header-case": "^2.0.4", + "no-case": "^3.0.4", + "param-case": "^3.0.4", + "pascal-case": "^3.1.2", + "path-case": "^3.0.4", + "sentence-case": "^3.0.4", + "snake-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/check-node-version": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/check-node-version/-/check-node-version-4.2.1.tgz", + "integrity": "sha512-YYmFYHV/X7kSJhuN/QYHUu998n/TRuDe8UenM3+m5NrkiH670lb9ILqHIvBencvJc4SDh+XcbXMR4b+TtubJiw==", + "dev": true, + "dependencies": { + "chalk": "^3.0.0", + "map-values": "^1.0.1", + "minimist": "^1.2.0", + "object-filter": "^1.0.2", + "run-parallel": "^1.1.4", + "semver": "^6.3.0" + }, + "bin": { + "check-node-version": "bin.js" + }, + "engines": { + "node": ">=8.3.0" + } + }, + "node_modules/check-node-version/node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", + "dev": true, + "dependencies": { + "readdirp": "^5.0.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/chrome-launcher": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-1.2.1.tgz", + "integrity": "sha512-qmFR5PLMzHyuNJHwOloHPAHhbaNglkfeV/xDtt5b7xiFFyU1I+AZZX0PYseMuhenJSSirgxELYIbswcoc+5H4A==", + "dev": true, + "dependencies": { + "@types/node": "*", + "escape-string-regexp": "^4.0.0", + "is-wsl": "^2.2.0", + "lighthouse-logger": "^2.0.1" + }, + "bin": { + "print-chrome-path": "bin/print-chrome-path.cjs" + }, + "engines": { + "node": ">=12.13.0" + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", + "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", + "dev": true, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/chromium-bidi": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.11.0.tgz", + "integrity": "sha512-6CJWHkNRoyZyjV9Rwv2lYONZf1Xm0IuDyNq97nwSsxxP3wf5Bwy15K5rOvVKMtJ127jJBmxFUanSAOjgFRxgrA==", + "dev": true, + "dependencies": { + "mitt": "3.0.1", + "zod": "3.23.8" + }, + "peerDependencies": { + "devtools-protocol": "*" + } + }, + "node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "node_modules/cjs-module-lexer": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz", + "integrity": "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==", + "dev": true + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/clone-deep": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-0.2.4.tgz", + "integrity": "sha512-we+NuQo2DHhSl+DP6jlUiAhyAjBQrYnpOk15rN6c6JSPScjiCLh8IbSU+VTcph6YS3o7mASE8a0+gbZ7ChLpgg==", + "dev": true, + "dependencies": { + "for-own": "^0.1.3", + "is-plain-object": "^2.0.1", + "kind-of": "^3.0.2", + "lazy-cache": "^1.0.3", + "shallow-clone": "^0.1.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/clone-deep/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true, + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.3.tgz", + "integrity": "sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==", + "dev": true + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/colord": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", + "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==", + "dev": true + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true + }, + "node_modules/colorjs.io": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/colorjs.io/-/colorjs.io-0.6.1.tgz", + "integrity": "sha512-8lyR2wHzuIykCpqHKgluGsqQi5iDm3/a2IgP2GBZrasn2sBRkE4NOGsglZxWLs/jZQoNkmA/KM/8NV16rLUdBg==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/color" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "dev": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/comment-parser": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.1.tgz", + "integrity": "sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==", + "dev": true, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/common-path-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", + "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==", + "dev": true + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dev": true, + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.1.tgz", + "integrity": "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "compressible": "~2.0.18", + "debug": "2.6.9", + "negotiator": "~0.6.4", + "on-headers": "~1.1.0", + "safe-buffer": "5.2.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/configstore": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-7.1.0.tgz", + "integrity": "sha512-N4oog6YJWbR9kGyXvS7jEykLDXIE2C0ILYqNBZBp9iwiJpoCBWYsuAdW6PPFn6w06jjnC+3JstVvWHO4cZqvRg==", + "dev": true, + "dependencies": { + "atomically": "^2.0.3", + "dot-prop": "^9.0.0", + "graceful-fs": "^4.2.11", + "xdg-basedir": "^5.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/connect-history-api-fallback": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/constant-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/constant-case/-/constant-case-3.0.4.tgz", + "integrity": "sha512-I2hSBi7Vvs7BEuJDr5dDHfzb/Ruj3FyvFyh7KLilAjNQw3Be+xgqUBA2W6scVEcL0hL1dwPRtIqEPVUCKkSsyQ==", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3", + "upper-case": "^2.0.2" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dev": true, + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz", + "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==", + "dev": true + }, + "node_modules/copy-webpack-plugin": { + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-10.2.4.tgz", + "integrity": "sha512-xFVltahqlsRcyyJqQbDY6EYTtyQZF9rf+JPjwHObLdPFMEISqkFkr7mFoVOC6BfYS/dNThyoQKvziugm+OnwBg==", + "dev": true, + "dependencies": { + "fast-glob": "^3.2.7", + "glob-parent": "^6.0.1", + "globby": "^12.0.2", + "normalize-path": "^3.0.0", + "schema-utils": "^4.0.0", + "serialize-javascript": "^6.0.0" + }, + "engines": { + "node": ">= 12.20.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + } + }, + "node_modules/copy-webpack-plugin/node_modules/array-union": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-3.0.1.tgz", + "integrity": "sha512-1OvF9IbWwaeiM9VhzYXVQacMibxpXOMYVNIvMtKRyX9SImBXpKcFr8XvFDeEslCyuH/t6KRt7HEO94AlP8Iatw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/copy-webpack-plugin/node_modules/globby": { + "version": "12.2.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-12.2.0.tgz", + "integrity": "sha512-wiSuFQLZ+urS9x2gGPl1H5drc5twabmm4m2gTR27XDFyjUHJUNsS8o/2aKyIF6IoBaR630atdher0XJ5g6OMmA==", + "dev": true, + "dependencies": { + "array-union": "^3.0.1", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.7", + "ignore": "^5.1.9", + "merge2": "^1.4.1", + "slash": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/copy-webpack-plugin/node_modules/slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/core-js": { + "version": "3.49.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.49.0.tgz", + "integrity": "sha512-es1U2+YTtzpwkxVLwAFdSpaIMyQaq0PBgm3YD1W3Qpsn1NAmO3KSgZfu+oGSWVu6NvLHoHCV/aYcsE5wiB7ALg==", + "dev": true, + "hasInstallScript": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-js-compat": { + "version": "3.49.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.49.0.tgz", + "integrity": "sha512-VQXt1jr9cBz03b331DFDCCP90b3fanciLkgiOoy8SBHy06gNf+vQ1A3WFLqG7I8TipYIKeYK9wxd0tUrvHcOZA==", + "dev": true, + "dependencies": { + "browserslist": "^4.28.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-js-pure": { + "version": "3.49.0", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.49.0.tgz", + "integrity": "sha512-XM4RFka59xATyJv/cS3O3Kml72hQXUeGRuuTmMYFxwzc9/7C8OYTaIR/Ji+Yt8DXzsFLNhat15cE/JP15HrCgw==", + "dev": true, + "hasInstallScript": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true + }, + "node_modules/cosmiconfig": { + "version": "8.3.6", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", + "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", + "dev": true, + "dependencies": { + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0", + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/cosmiconfig/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/cosmiconfig/node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/create-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", + "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "prompts": "^2.0.1" + }, + "bin": { + "create-jest": "bin/create-jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/csp_evaluator": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/csp_evaluator/-/csp_evaluator-1.1.5.tgz", + "integrity": "sha512-EL/iN9etCTzw/fBnp0/uj0f5BOOGvZut2mzsiiBZ/FdT6gFQCKRO/tmcKOxn5drWZ2Ndm/xBb1SI4zwWbGtmIw==", + "dev": true + }, + "node_modules/css-declaration-sorter": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-7.4.0.tgz", + "integrity": "sha512-LTuzjPoyA2vMGKKcaOqKSp7Ub2eGrNfKiZH4LpezxpNrsICGCSFvsQOI29psISxNZtaXibkC2CXzrQ5enMeGGw==", + "dev": true, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.0.9" + } + }, + "node_modules/css-functions-list": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/css-functions-list/-/css-functions-list-3.3.3.tgz", + "integrity": "sha512-8HFEBPKhOpJPEPu70wJJetjKta86Gw9+CCyCnB3sui2qQfOvRyqBy4IKLKKAwdMpWb2lHXWk9Wb4Z6AmaUT1Pg==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/css-loader": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.11.0.tgz", + "integrity": "sha512-CTJ+AEQJjq5NzLga5pE39qdiSV56F8ywCIsqNIRF0r7BDgWsN25aazToqAFg7ZrtA/U016xudB3ffgweORxX7g==", + "dev": true, + "dependencies": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.33", + "postcss-modules-extract-imports": "^3.1.0", + "postcss-modules-local-by-default": "^4.0.5", + "postcss-modules-scope": "^3.2.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/css-loader/node_modules/semver": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz", + "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/css-select": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz", + "integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-tree": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.2.1.tgz", + "integrity": "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==", + "dev": true, + "dependencies": { + "mdn-data": "2.27.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, + "node_modules/css-what": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz", + "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==", + "dev": true, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cssnano": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-6.1.2.tgz", + "integrity": "sha512-rYk5UeX7VAM/u0lNqewCdasdtPK81CgX8wJFLEIXHbV2oldWRgJAsZrdhRXkV1NJzA2g850KiFm9mMU2HxNxMA==", + "dev": true, + "dependencies": { + "cssnano-preset-default": "^6.1.2", + "lilconfig": "^3.1.1" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/cssnano" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/cssnano-preset-default": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-6.1.2.tgz", + "integrity": "sha512-1C0C+eNaeN8OcHQa193aRgYexyJtU8XwbdieEjClw+J9d94E41LwT6ivKH0WT+fYwYWB0Zp3I3IZ7tI/BbUbrg==", + "dev": true, + "dependencies": { + "browserslist": "^4.23.0", + "css-declaration-sorter": "^7.2.0", + "cssnano-utils": "^4.0.2", + "postcss-calc": "^9.0.1", + "postcss-colormin": "^6.1.0", + "postcss-convert-values": "^6.1.0", + "postcss-discard-comments": "^6.0.2", + "postcss-discard-duplicates": "^6.0.3", + "postcss-discard-empty": "^6.0.3", + "postcss-discard-overridden": "^6.0.2", + "postcss-merge-longhand": "^6.0.5", + "postcss-merge-rules": "^6.1.1", + "postcss-minify-font-values": "^6.1.0", + "postcss-minify-gradients": "^6.0.3", + "postcss-minify-params": "^6.1.0", + "postcss-minify-selectors": "^6.0.4", + "postcss-normalize-charset": "^6.0.2", + "postcss-normalize-display-values": "^6.0.2", + "postcss-normalize-positions": "^6.0.2", + "postcss-normalize-repeat-style": "^6.0.2", + "postcss-normalize-string": "^6.0.2", + "postcss-normalize-timing-functions": "^6.0.2", + "postcss-normalize-unicode": "^6.1.0", + "postcss-normalize-url": "^6.0.2", + "postcss-normalize-whitespace": "^6.0.2", + "postcss-ordered-values": "^6.0.2", + "postcss-reduce-initial": "^6.1.0", + "postcss-reduce-transforms": "^6.0.2", + "postcss-svgo": "^6.0.3", + "postcss-unique-selectors": "^6.0.4" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/cssnano-utils": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-4.0.2.tgz", + "integrity": "sha512-ZR1jHg+wZ8o4c3zqf1SIUSTIvm/9mU343FMR6Obe/unskbvpGhZOo1J6d/r8D1pzkRQYuwbcH3hToOuoA2G7oQ==", + "dev": true, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/csso": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", + "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", + "dev": true, + "dependencies": { + "css-tree": "~2.2.0" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/css-tree": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", + "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", + "dev": true, + "dependencies": { + "mdn-data": "2.0.28", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/mdn-data": { + "version": "2.0.28", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", + "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", + "dev": true + }, + "node_modules/cssom": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz", + "integrity": "sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==", + "dev": true + }, + "node_modules/cssstyle": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", + "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "dev": true, + "dependencies": { + "cssom": "~0.3.6" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cssstyle/node_modules/cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", + "dev": true + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==" + }, + "node_modules/cwd": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/cwd/-/cwd-0.10.0.tgz", + "integrity": "sha512-YGZxdTTL9lmLkCUTpg4j0zQ7IhRB5ZmqNBbGCl3Tg6MP/d5/6sY7L5mmTjzbc6JKgVZYiqTQTNhPFsbXNGlRaA==", + "dev": true, + "dependencies": { + "find-pkg": "^0.1.2", + "fs-exists-sync": "^0.1.0" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/damerau-levenshtein": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", + "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", + "dev": true + }, + "node_modules/data-uri-to-buffer": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz", + "integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==", + "dev": true, + "engines": { + "node": ">= 14" + } + }, + "node_modules/data-urls": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-3.0.2.tgz", + "integrity": "sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==", + "dev": true, + "dependencies": { + "abab": "^2.0.6", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^11.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/data-view-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", + "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", + "dev": true, + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", + "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", + "dev": true, + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/inspect-js" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", + "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", + "dev": true, + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/debounce": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz", + "integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==", + "dev": true + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decamelize-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.1.tgz", + "integrity": "sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==", + "dev": true, + "dependencies": { + "decamelize": "^1.1.0", + "map-obj": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decamelize-keys/node_modules/map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decimal.js": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", + "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", + "dev": true + }, + "node_modules/dedent": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.2.tgz", + "integrity": "sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==", + "dev": true, + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/default-gateway": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", + "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", + "dev": true, + "dependencies": { + "execa": "^5.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/degenerator": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz", + "integrity": "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==", + "dev": true, + "dependencies": { + "ast-types": "^0.13.4", + "escodegen": "^2.1.0", + "esprima": "^4.0.1" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "dev": true, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", + "dev": true + }, + "node_modules/devtools-protocol": { + "version": "0.0.1507524", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1507524.tgz", + "integrity": "sha512-OjaNE7qpk6GRTXtqQjAE5bGx6+c4F1zZH0YXtpZQLM92HNXx4zMAaqlKhP4T52DosG6hDW8gPMNhGOF8xbwk/w==", + "dev": true + }, + "node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dns-packet": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", + "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", + "dev": true, + "dependencies": { + "@leichtgewicht/ip-codec": "^2.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dev": true, + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domexception": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", + "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==", + "deprecated": "Use your platform's native DOMException instead", + "dev": true, + "dependencies": { + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dev": true, + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", + "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", + "dev": true, + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/dot-prop": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-9.0.0.tgz", + "integrity": "sha512-1gxPBJpI/pcjQhKgIU91II6Wkay+dLcN3M6rf2uwP8hRur3HtQXjVrdAK3sjC0piaEuxzMwjXChcETiJl47lAQ==", + "dev": true, + "dependencies": { + "type-fest": "^4.18.2" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/dot-prop/node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "dev": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", + "dev": true + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "dev": true + }, + "node_modules/electron-to-chromium": { + "version": "1.5.361", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.361.tgz", + "integrity": "sha512-Q6Hts7N9FnJc5LeGRINFvLhCI9xZmNtTDe5ZbcVezQz7cU4a8Aua3GH1b8J2XY8Al9PF+OCwYqhgsOOheMdvkA==", + "dev": true + }, + "node_modules/emittery": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "dev": true, + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.22.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.22.0.tgz", + "integrity": "sha512-xYcDWrpELkFzz9SpZ3PlI6Eu6eD93Yf0WLDRxikGhWJ3MAir2SNZTIVCVZqZ/NUyx8AdMc2gT9C0gPiw18kG+A==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.3.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/enquirer": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", + "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", + "dev": true, + "dependencies": { + "ansi-colors": "^4.1.1", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/envinfo": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.21.0.tgz", + "integrity": "sha512-Lw7I8Zp5YKHFCXL7+Dz95g4CcbMEpgvqZNNq3AmlT5XAV6CgAAk6gyAMqn2zjw08K9BHfcNuKrMiCPLByGafow==", + "dev": true, + "bin": { + "envinfo": "dist/cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/error-stack-parser": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz", + "integrity": "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==", + "dev": true, + "dependencies": { + "stackframe": "^1.3.4" + } + }, + "node_modules/es-abstract": { + "version": "1.24.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.2.tgz", + "integrity": "sha512-2FpH9Q5i2RRwyEP1AylXe6nYLR5OhaJTZwmlcP0dL/+JCbgg7yyEo/sEK6HeGZRf3dFpWwThaRHVApXSkW3xeg==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.2", + "arraybuffer.prototype.slice": "^1.0.4", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "data-view-buffer": "^1.0.2", + "data-view-byte-length": "^1.0.2", + "data-view-byte-offset": "^1.0.1", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-set-tostringtag": "^2.1.0", + "es-to-primitive": "^1.3.0", + "function.prototype.name": "^1.1.8", + "get-intrinsic": "^1.3.0", + "get-proto": "^1.0.1", + "get-symbol-description": "^1.1.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "internal-slot": "^1.1.0", + "is-array-buffer": "^3.0.5", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.2", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.2.1", + "is-set": "^2.0.3", + "is-shared-array-buffer": "^1.0.4", + "is-string": "^1.1.1", + "is-typed-array": "^1.1.15", + "is-weakref": "^1.1.1", + "math-intrinsics": "^1.1.0", + "object-inspect": "^1.13.4", + "object-keys": "^1.1.1", + "object.assign": "^4.1.7", + "own-keys": "^1.0.1", + "regexp.prototype.flags": "^1.5.4", + "safe-array-concat": "^1.1.3", + "safe-push-apply": "^1.0.0", + "safe-regex-test": "^1.1.0", + "set-proto": "^1.0.0", + "stop-iteration-iterator": "^1.1.0", + "string.prototype.trim": "^1.2.10", + "string.prototype.trimend": "^1.0.9", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.3", + "typed-array-byte-length": "^1.0.3", + "typed-array-byte-offset": "^1.0.4", + "typed-array-length": "^1.0.7", + "unbox-primitive": "^1.1.0", + "which-typed-array": "^1.1.19" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-iterator-helpers": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.3.2.tgz", + "integrity": "sha512-HVLACW1TppGYjJ8H6/jqH/pqOtKRw6wMlrB23xfExmFWxFquAIWCmwoLsOyN96K4a5KbmOf5At9ZUO3GZbetAw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.24.2", + "es-errors": "^1.3.0", + "es-set-tostringtag": "^2.1.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.3.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "internal-slot": "^1.1.0", + "iterator.prototype": "^1.1.5", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.1.0.tgz", + "integrity": "sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==", + "dev": true + }, + "node_modules/es-object-atoms": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz", + "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-to-primitive": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", + "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", + "dev": true, + "dependencies": { + "is-callable": "^1.2.7", + "is-date-object": "^1.0.5", + "is-symbol": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "dev": true + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/escodegen": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", + "dev": true, + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/escodegen/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", + "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", + "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.1", + "@humanwhocodes/config-array": "^0.13.0", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-prettier": { + "version": "8.10.2", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.10.2.tgz", + "integrity": "sha512-/IGJ6+Dka158JnP5n5YFMOszjDWrXggGz1LaK/guZq9vZTmniaKlHcsscvkAhn9y4U+BU3JuUdYvtAMcv30y4A==", + "dev": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-import-context": { + "version": "0.1.9", + "resolved": "https://registry.npmjs.org/eslint-import-context/-/eslint-import-context-0.1.9.tgz", + "integrity": "sha512-K9Hb+yRaGAGUbwjhFNHvSmmkZs9+zbuoe3kFQ4V1wYjrepUFYM2dZAfNtjbbj3qsPfUfsA68Bx/ICWQMi+C8Eg==", + "dev": true, + "dependencies": { + "get-tsconfig": "^4.10.1", + "stable-hash-x": "^0.2.0" + }, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-import-context" + }, + "peerDependencies": { + "unrs-resolver": "^1.0.0" + }, + "peerDependenciesMeta": { + "unrs-resolver": { + "optional": true + } + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.10", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.10.tgz", + "integrity": "sha512-tRrKqFyCaKict5hOd244sL6EQFNycnMQnBe+j8uqGNXYzsImGbGUU4ibtoaBmv5FLwJwcFJNeg1GeVjQfbMrDQ==", + "dev": true, + "dependencies": { + "debug": "^3.2.7", + "is-core-module": "^2.16.1", + "resolve": "^2.0.0-next.6" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/resolve": { + "version": "2.0.0-next.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.7.tgz", + "integrity": "sha512-tqt+NBWwyaMgw3zDsnygx4CByWjQEJHOPMdslYhppaQSJUtL/D4JO9CcBBlhPoI8lz9oJIDXkwXfhF4aWqP8xQ==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.2", + "node-exports-info": "^1.6.0", + "object-keys": "^1.1.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/eslint-import-resolver-typescript": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-4.4.4.tgz", + "integrity": "sha512-1iM2zeBvrYmUNTj2vSC/90JTHDth+dfOfiNKkxApWRsTJYNrc8rOdxxIf5vazX+BiAXTeOT0UvWpGI/7qIWQOw==", + "dev": true, + "dependencies": { + "debug": "^4.4.1", + "eslint-import-context": "^0.1.8", + "get-tsconfig": "^4.10.1", + "is-bun-module": "^2.0.0", + "stable-hash-x": "^0.2.0", + "tinyglobby": "^0.2.14", + "unrs-resolver": "^1.7.11" + }, + "engines": { + "node": "^16.17.0 || >=18.6.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-import-resolver-typescript" + }, + "peerDependencies": { + "eslint": "*", + "eslint-plugin-import": "*", + "eslint-plugin-import-x": "*" + }, + "peerDependenciesMeta": { + "eslint-plugin-import": { + "optional": true + }, + "eslint-plugin-import-x": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.1.tgz", + "integrity": "sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==", + "dev": true, + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.32.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz", + "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", + "dev": true, + "dependencies": { + "@rtsao/scc": "^1.1.0", + "array-includes": "^3.1.9", + "array.prototype.findlastindex": "^1.2.6", + "array.prototype.flat": "^1.3.3", + "array.prototype.flatmap": "^1.3.3", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-module-utils": "^2.12.1", + "hasown": "^2.0.2", + "is-core-module": "^2.16.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.8", + "object.groupby": "^1.0.3", + "object.values": "^1.2.1", + "semver": "^6.3.1", + "string.prototype.trimend": "^1.0.9", + "tsconfig-paths": "^3.15.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" + } + }, + "node_modules/eslint-plugin-import/node_modules/brace-expansion": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint-plugin-jest": { + "version": "27.9.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-27.9.0.tgz", + "integrity": "sha512-QIT7FH7fNmd9n4se7FFKHbsLKGQiw885Ds6Y/sxKgCZ6natwCsXdgPOADnYVxN2QrRweF0FZWbJ6S7Rsn7llug==", + "dev": true, + "dependencies": { + "@typescript-eslint/utils": "^5.10.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@typescript-eslint/eslint-plugin": "^5.0.0 || ^6.0.0 || ^7.0.0", + "eslint": "^7.0.0 || ^8.0.0", + "jest": "*" + }, + "peerDependenciesMeta": { + "@typescript-eslint/eslint-plugin": { + "optional": true + }, + "jest": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-jest/node_modules/@typescript-eslint/scope-manager": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", + "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/eslint-plugin-jest/node_modules/@typescript-eslint/types": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", + "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/eslint-plugin-jest/node_modules/@typescript-eslint/typescript-estree": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", + "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-jest/node_modules/@typescript-eslint/utils": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz", + "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", + "eslint-scope": "^5.1.1", + "semver": "^7.3.7" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/eslint-plugin-jest/node_modules/@typescript-eslint/visitor-keys": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", + "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/eslint-plugin-jest/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-plugin-jest/node_modules/semver": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz", + "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-plugin-jsdoc": { + "version": "46.10.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-46.10.1.tgz", + "integrity": "sha512-x8wxIpv00Y50NyweDUpa+58ffgSAI5sqe+zcZh33xphD0AVh+1kqr1ombaTRb7Fhpove1zfUuujlX9DWWBP5ag==", + "dev": true, + "dependencies": { + "@es-joy/jsdoccomment": "~0.41.0", + "are-docs-informative": "^0.0.2", + "comment-parser": "1.4.1", + "debug": "^4.3.4", + "escape-string-regexp": "^4.0.0", + "esquery": "^1.5.0", + "is-builtin-module": "^3.2.1", + "semver": "^7.5.4", + "spdx-expression-parse": "^4.0.0" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-jsdoc/node_modules/semver": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz", + "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-plugin-jsx-a11y": { + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.10.2.tgz", + "integrity": "sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==", + "dev": true, + "dependencies": { + "aria-query": "^5.3.2", + "array-includes": "^3.1.8", + "array.prototype.flatmap": "^1.3.2", + "ast-types-flow": "^0.0.8", + "axe-core": "^4.10.0", + "axobject-query": "^4.1.0", + "damerau-levenshtein": "^1.0.8", + "emoji-regex": "^9.2.2", + "hasown": "^2.0.2", + "jsx-ast-utils": "^3.3.5", + "language-tags": "^1.0.9", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.8", + "safe-regex-test": "^1.0.3", + "string.prototype.includes": "^2.0.1" + }, + "engines": { + "node": ">=4.0" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9" + } + }, + "node_modules/eslint-plugin-jsx-a11y/node_modules/brace-expansion": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint-plugin-jsx-a11y/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint-plugin-playwright": { + "version": "0.15.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-playwright/-/eslint-plugin-playwright-0.15.3.tgz", + "integrity": "sha512-LQMW5y0DLK5Fnpya7JR1oAYL2/7Y9wDiYw6VZqlKqcRGSgjbVKNqxraphk7ra1U3Bb5EK444xMgUlQPbMg2M1g==", + "dev": true, + "peerDependencies": { + "eslint": ">=7", + "eslint-plugin-jest": ">=25" + }, + "peerDependenciesMeta": { + "eslint-plugin-jest": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-prettier": { + "version": "5.5.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.5.tgz", + "integrity": "sha512-hscXkbqUZ2sPithAuLm5MXL+Wph+U7wHngPBv9OMWwlP8iaflyxpjTYZkmdgB4/vPIhemRlBEoLrH7UC1n7aUw==", + "dev": true, + "dependencies": { + "prettier-linter-helpers": "^1.0.1", + "synckit": "^0.11.12" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-plugin-prettier" + }, + "peerDependencies": { + "@types/eslint": ">=8.0.0", + "eslint": ">=8.0.0", + "eslint-config-prettier": ">= 7.0.0 <10.0.0 || >=10.1.0", + "prettier": ">=3.0.0" + }, + "peerDependenciesMeta": { + "@types/eslint": { + "optional": true + }, + "eslint-config-prettier": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-react": { + "version": "7.37.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz", + "integrity": "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.8", + "array.prototype.findlast": "^1.2.5", + "array.prototype.flatmap": "^1.3.3", + "array.prototype.tosorted": "^1.1.4", + "doctrine": "^2.1.0", + "es-iterator-helpers": "^1.2.1", + "estraverse": "^5.3.0", + "hasown": "^2.0.2", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.9", + "object.fromentries": "^2.0.8", + "object.values": "^1.2.1", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.5", + "semver": "^6.3.1", + "string.prototype.matchall": "^4.0.12", + "string.prototype.repeat": "^1.0.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.2.tgz", + "integrity": "sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/eslint-plugin-react/node_modules/brace-expansion": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint-plugin-react/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-react/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint-plugin-react/node_modules/resolve": { + "version": "2.0.0-next.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.7.tgz", + "integrity": "sha512-tqt+NBWwyaMgw3zDsnygx4CByWjQEJHOPMdslYhppaQSJUtL/D4JO9CcBBlhPoI8lz9oJIDXkwXfhF4aWqP8xQ==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.2", + "node-exports-info": "^1.6.0", + "object-keys": "^1.1.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-scope/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/eslint/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/events-universal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/events-universal/-/events-universal-1.0.1.tgz", + "integrity": "sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==", + "dev": true, + "dependencies": { + "bare-events": "^2.7.0" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expand-tilde": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-1.2.2.tgz", + "integrity": "sha512-rtmc+cjLZqnu9dSYosX9EWmSJhTwpACgJQTfj4hgg2JjOD/6SIQalZrt4a3aQeh++oNxkazcaxrhPUj6+g5G/Q==", + "dev": true, + "dependencies": { + "os-homedir": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", + "dev": true, + "dependencies": { + "@jest/expect-utils": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/expect-puppeteer": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/expect-puppeteer/-/expect-puppeteer-4.4.0.tgz", + "integrity": "sha512-6Ey4Xy2xvmuQu7z7YQtMsaMV0EHJRpVxIDOd5GRrm04/I3nkTKIutELfECsLp6le+b3SSa3cXhPiw6PgqzxYWA==", + "dev": true + }, + "node_modules/express": { + "version": "4.22.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.22.2.tgz", + "integrity": "sha512-IuL+Elrou2ZvCFHs18/CIzy2Nzvo25nZ1/D2eIZlz7c+QUayAcYoiM2BthCjs+EBHVpjYjcuLDAiCWgeIX3X1Q==", + "dev": true, + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "~1.20.5", + "content-disposition": "~0.5.4", + "content-type": "~1.0.4", + "cookie": "~0.7.1", + "cookie-signature": "~1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.3.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "~2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "~0.1.12", + "proxy-addr": "~2.0.7", + "qs": "~6.15.1", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "~0.19.0", + "serve-static": "~1.16.2", + "setprototypeof": "1.2.0", + "statuses": "~2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/extract-zip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", + "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" + }, + "bin": { + "extract-zip": "cli.js" + }, + "engines": { + "node": ">= 10.17.0" + }, + "optionalDependencies": { + "@types/yauzl": "^2.9.1" + } + }, + "node_modules/extract-zip/node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true + }, + "node_modules/fast-fifo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fast-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.2.tgz", + "integrity": "sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ] + }, + "node_modules/fastest-levenshtein": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", + "dev": true, + "engines": { + "node": ">= 4.9.1" + } + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "dev": true, + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "dev": true, + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "dev": true, + "dependencies": { + "pend": "~1.2.0" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/filename-reserved-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz", + "integrity": "sha512-lc1bnsSr4L4Bdif8Xb/qrtokGbq5zlsms/CYH8PP+WtCkGNF65DPiQY8vG3SakEdRn8Dlnm+gW/qWKKjS5sZzQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/filenamify": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-4.3.0.tgz", + "integrity": "sha512-hcFKyUG57yWGAzu1CMt/dPzYZuv+jAJUT85bL8mrXvNe6hWj6yEHEc4EdcgiA6Z3oi1/9wXJdZPXF2dZNgwgOg==", + "dev": true, + "dependencies": { + "filename-reserved-regex": "^2.0.0", + "strip-outer": "^1.0.1", + "trim-repeated": "^1.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz", + "integrity": "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "~2.4.1", + "parseurl": "~1.3.3", + "statuses": "~2.0.2", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/find-cache-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-4.0.0.tgz", + "integrity": "sha512-9ZonPT4ZAK4a+1pUPVPZJapbi7O5qbbJPdYw/NOQWZZbVLdDTYM3A4R9z/DpAM08IDaFGsvPgiGZ82WEwUDWjg==", + "dev": true, + "dependencies": { + "common-path-prefix": "^3.0.0", + "pkg-dir": "^7.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-file-up": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/find-file-up/-/find-file-up-0.1.3.tgz", + "integrity": "sha512-mBxmNbVyjg1LQIIpgO8hN+ybWBgDQK8qjht+EbrTCGmmPV/sc7RF1i9stPTD6bpvXZywBdrwRYxhSdJv867L6A==", + "dev": true, + "dependencies": { + "fs-exists-sync": "^0.1.0", + "resolve-dir": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/find-parent-dir": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/find-parent-dir/-/find-parent-dir-0.3.1.tgz", + "integrity": "sha512-o4UcykWV/XN9wm+jMEtWLPlV8RXCZnMhQI6F6OdHeSez7iiJWePw8ijOlskJZMsaQoGR/b7dH6lO02HhaTN7+A==", + "dev": true + }, + "node_modules/find-pkg": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/find-pkg/-/find-pkg-0.1.2.tgz", + "integrity": "sha512-0rnQWcFwZr7eO0513HahrWafsc3CTFioEB7DRiEYCUM/70QXSY8f3mCST17HXLcPvEhzH/Ty/Bxd72ZZsr/yvw==", + "dev": true, + "dependencies": { + "find-file-up": "^0.1.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/find-process": { + "version": "1.4.11", + "resolved": "https://registry.npmjs.org/find-process/-/find-process-1.4.11.tgz", + "integrity": "sha512-mAOh9gGk9WZ4ip5UjV0o6Vb4SrfnAmtsFNzkMRH9HQiFXVQnDyQFrSHTK5UoG6E+KV+s+cIznbtwpfN41l2nFA==", + "dev": true, + "dependencies": { + "chalk": "~4.1.2", + "commander": "^12.1.0", + "loglevel": "^1.9.2" + }, + "bin": { + "find-process": "bin/find-process.js" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", + "dev": true + }, + "node_modules/follow-redirects": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz", + "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "dev": true, + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/for-own": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", + "integrity": "sha512-SKmowqGTJoPzLO1T0BBJpkfp3EMacCMOuH40hOUbrbzElVktk4DioXVM99QkLCyKoiuOmyjgcWMpVz2xjE7LZw==", + "dev": true, + "dependencies": { + "for-in": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/form-data": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/forwarded-parse": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/forwarded-parse/-/forwarded-parse-2.1.2.tgz", + "integrity": "sha512-alTFZZQDKMporBH77856pXgzhEzaUVmLCDk+egLgIgHst3Tpndzz8MnKe+GzRJRfvVdn69HhpW7cmXzvtLvJAw==", + "dev": true + }, + "node_modules/fraction.js": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz", + "integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==", + "dev": true, + "engines": { + "node": "*" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-exists-sync": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz", + "integrity": "sha512-cR/vflFyPZtrN6b38ZyWxpWdhlXrzZEBawlpBQMq7033xVY7/kg0GDMBK5jg8lDYQckdJ5x/YC88lM3C7VMsLg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fs-monkey": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.1.0.tgz", + "integrity": "sha512-QMUezzXWII9EV5aTFXW1UBVUO77wYPpjqIF8/AviUCThNeSYZykpoTixUeaNNBwmCev0AMDWMAni+f8Hxb1IFw==", + "dev": true + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", + "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "functions-have-names": "^1.2.3", + "hasown": "^2.0.2", + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/generator-function": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", + "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-port": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-5.1.1.tgz", + "integrity": "sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-stdin": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-9.0.0.tgz", + "integrity": "sha512-dVKBjfWisLAicarI2Sf+JuBE/DghV4UzNAVe9yhEJuzeREd3JhOTE9cUaJTeSa77fsbQUK3pcOpJfM59+VKZaA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-symbol-description": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", + "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", + "dev": true, + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-tsconfig": { + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.14.0.tgz", + "integrity": "sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==", + "dev": true, + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/get-uri": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.5.tgz", + "integrity": "sha512-b1O07XYq8eRuVzBNgJLstU6FYc1tS6wnMtF1I1D9lE8LxZSOGZ7LhxN54yPP6mGw5f2CkXY2BQUL9Fx41qvcIg==", + "dev": true, + "dependencies": { + "basic-ftp": "^5.0.2", + "data-uri-to-buffer": "^6.0.2", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/gettext-parser": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/gettext-parser/-/gettext-parser-1.4.0.tgz", + "integrity": "sha512-sedZYLHlHeBop/gZ1jdg59hlUEcpcZJofLq2JFwJT1zTqAU3l2wFv6IsuwFHGqbiT9DWzMUW4/em2+hspnmMMA==", + "dependencies": { + "encoding": "^0.1.12", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/global-modules": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-0.2.3.tgz", + "integrity": "sha512-JeXuCbvYzYXcwE6acL9V2bAOeSIGl4dD+iwLY9iUx2VBJJ80R18HCn+JCwHM9Oegdfya3lEkGCdaRkSyc10hDA==", + "dev": true, + "dependencies": { + "global-prefix": "^0.1.4", + "is-windows": "^0.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/global-prefix": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-0.1.5.tgz", + "integrity": "sha512-gOPiyxcD9dJGCEArAhF4Hd0BAqvAe/JzERP7tYumE4yIkmIedPUVXcJFWbV3/p/ovIIvKjkrTk+f1UVkq7vvbw==", + "dev": true, + "dependencies": { + "homedir-polyfill": "^1.0.0", + "ini": "^1.3.4", + "is-windows": "^0.2.0", + "which": "^1.2.12" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/global-prefix/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "dev": true, + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globjoin": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/globjoin/-/globjoin-0.1.4.tgz", + "integrity": "sha512-xYfnw62CKG8nLkZBfWbhWwDw02CHty86jfPcc2cr3ZfeuK9ysoVPPEUxf21bAD/rWAgk52SuBrLJlefNy8mvFg==", + "dev": true + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, + "node_modules/gzip-size": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz", + "integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==", + "dev": true, + "dependencies": { + "duplexer": "^0.1.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", + "dev": true + }, + "node_modules/hard-rejection": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", + "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/has-bigints": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", + "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", + "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", + "dev": true, + "dependencies": { + "dunder-proto": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hashery": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/hashery/-/hashery-1.5.1.tgz", + "integrity": "sha512-iZyKG96/JwPz1N55vj2Ie2vXbhu440zfUfJvSwEqEbeLluk7NnapfGqa7LH0mOsnDxTF85Mx8/dyR6HfqcbmbQ==", + "dev": true, + "dependencies": { + "hookified": "^1.15.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/hasown": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.3.tgz", + "integrity": "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/header-case": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/header-case/-/header-case-2.0.4.tgz", + "integrity": "sha512-H/vuk5TEEVZwrR0lp2zed9OCo1uAILMlx0JEMgC26rzyJJ3N1v6XkwHHXJQdR2doSjcGPM6OKPYoJgf0plJ11Q==", + "dependencies": { + "capital-case": "^1.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/homedir-polyfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "dev": true, + "dependencies": { + "parse-passwd": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/hookified": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/hookified/-/hookified-1.15.1.tgz", + "integrity": "sha512-MvG/clsADq1GPM2KGo2nyfaWVyn9naPiXrqIe4jYjXNZQt238kWyOGrsyc/DmRAQ+Re6yeo6yX/yoNCG5KAEVg==", + "dev": true + }, + "node_modules/hosted-git-info": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/hosted-git-info/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/hosted-git-info/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "node_modules/hpack.js/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "node_modules/hpack.js/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/hpack.js/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/hpack.js/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/html-encoding-sniffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", + "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", + "dev": true, + "dependencies": { + "whatwg-encoding": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/html-entities": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.6.0.tgz", + "integrity": "sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/mdevils" + }, + { + "type": "patreon", + "url": "https://patreon.com/mdevils" + } + ] + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "node_modules/html-tags": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.3.1.tgz", + "integrity": "sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", + "dev": true + }, + "node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "dev": true, + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/http-link-header": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/http-link-header/-/http-link-header-1.1.3.tgz", + "integrity": "sha512-3cZ0SRL8fb9MUlU3mKM61FcQvPfXx2dBrZW3Vbg5CXa8jFlK8OaEpePenLe1oEXQduhz8b0QjsqfS59QP4AJDQ==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/http-parser-js": { + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.10.tgz", + "integrity": "sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA==", + "dev": true + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dev": true, + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "dev": true, + "dependencies": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/http-proxy-middleware": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.9.tgz", + "integrity": "sha512-c1IyJYLYppU574+YI7R4QyX2ystMtVXZwIdzazUIPIJsHuWNd+mho2j+bKoHftndicGj9yh+xjd+l0yj7VeT1Q==", + "dev": true, + "dependencies": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "@types/express": "^4.17.13" + }, + "peerDependenciesMeta": { + "@types/express": { + "optional": true + } + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/ignore-walk": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-4.0.1.tgz", + "integrity": "sha512-rzDQLaW4jQbh2YrOFlJdCtX8qgJTehFRYiUB2r1osqTeDzV/3+Jh8fz1oAPzUThf3iku8Ds4IDqawI5d8mUiQw==", + "dev": true, + "dependencies": { + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ignore-walk/node_modules/brace-expansion": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/ignore-walk/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/image-ssim": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/image-ssim/-/image-ssim-0.2.0.tgz", + "integrity": "sha512-W7+sO6/yhxy83L0G7xR8YAc5Z5QFtYEXXRV6EaE8tuYBZJnA3gVgp3q7X7muhLZVodeb9UfvjSbwt9VJwjIYAg==", + "dev": true + }, + "node_modules/immutable": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.5.tgz", + "integrity": "sha512-t7xcm2siw+hlUM68I+UEOK+z84RzmN59as9DZ7P1l0994DKUWV7UXBMQZVxaoMSRQ+PBZbHCOoBt7a2wxOMt+A==", + "dev": true + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/import-in-the-middle": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/import-in-the-middle/-/import-in-the-middle-1.15.0.tgz", + "integrity": "sha512-bpQy+CrsRmYmoPMAE/0G33iwRqwW4ouqdRg8jgbH3aKuCtOc8lxgmYXg2dMM92CRiGP660EtBcymH/eVUpCSaA==", + "dev": true, + "dependencies": { + "acorn": "^8.14.0", + "acorn-import-attributes": "^1.9.5", + "cjs-module-lexer": "^1.2.2", + "module-details-from-path": "^1.0.3" + } + }, + "node_modules/import-local": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", + "dev": true, + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-local/node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "node_modules/internal-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", + "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/interpret": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", + "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/intl-messageformat": { + "version": "10.7.18", + "resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-10.7.18.tgz", + "integrity": "sha512-m3Ofv/X/tV8Y3tHXLohcuVuhWKo7BBq62cqY15etqmLxg2DZ34AGGgQDeR+SCta2+zICb1NX83af0GJmbQ1++g==", + "dev": true, + "dependencies": { + "@formatjs/ecma402-abstract": "2.3.6", + "@formatjs/fast-memoize": "2.2.7", + "@formatjs/icu-messageformat-parser": "2.11.4", + "tslib": "^2.8.0" + } + }, + "node_modules/ip-address": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.2.0.tgz", + "integrity": "sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==", + "dev": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/ipaddr.js": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.4.0.tgz", + "integrity": "sha512-9VGk3HGanVE6JoZXHiCpnGy5X0jYDnN4EA4lntFPj+1vIWlFhIylq2CrrCOJH9EAhc5CYhq18F2Av2tgoAPsYQ==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/irregular-plurals": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/irregular-plurals/-/irregular-plurals-3.5.0.tgz", + "integrity": "sha512-1ANGLZ+Nkv1ptFb2pa8oG8Lem4krflKuX/gINiHJHjJUKaJHk/SXk5x6K3J+39/p0h1RQ2saROclJJ+QLvETCQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", + "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "node_modules/is-async-function": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", + "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", + "dev": true, + "dependencies": { + "async-function": "^1.0.0", + "call-bound": "^1.0.3", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", + "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", + "dev": true, + "dependencies": { + "has-bigints": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-boolean-object": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", + "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", + "dev": true, + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "node_modules/is-builtin-module": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz", + "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==", + "dev": true, + "dependencies": { + "builtin-modules": "^3.3.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-bun-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-bun-module/-/is-bun-module-2.0.0.tgz", + "integrity": "sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==", + "dev": true, + "dependencies": { + "semver": "^7.7.1" + } + }, + "node_modules/is-bun-module/node_modules/semver": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz", + "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz", + "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==", + "dev": true, + "dependencies": { + "hasown": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", + "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", + "dev": true, + "dependencies": { + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", + "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", + "dev": true, + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true, + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-finalizationregistry": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", + "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", + "dev": true, + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/is-generator-function": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", + "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", + "dev": true, + "dependencies": { + "call-bound": "^1.0.4", + "generator-function": "^2.0.0", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", + "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", + "dev": true, + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true + }, + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "dev": true, + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", + "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", + "dev": true, + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-string": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", + "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", + "dev": true, + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", + "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", + "dev": true, + "dependencies": { + "call-bound": "^1.0.2", + "has-symbols": "^1.1.0", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "dev": true, + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", + "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", + "dev": true, + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", + "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", + "dev": true, + "dependencies": { + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-windows": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-0.2.0.tgz", + "integrity": "sha512-n67eJYmXbniZB7RF4I/FTjK1s6RPOCTxhYrVYLRaCt3lF0mpWZPKr3T2LSZAqyjQsxR2qMmGYXXzK0YWwcPM1Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "dev": true, + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/istanbul-reports": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", + "dev": true, + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/iterator.prototype": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.5.tgz", + "integrity": "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.4", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.6", + "get-proto": "^1.0.0", + "has-symbols": "^1.1.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", + "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", + "dev": true, + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/types": "^29.6.3", + "import-local": "^3.0.2", + "jest-cli": "^29.7.0" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-changed-files": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz", + "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==", + "dev": true, + "dependencies": { + "execa": "^5.0.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz", + "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^1.0.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^29.7.0", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0", + "pretty-format": "^29.7.0", + "pure-rand": "^6.0.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-cli": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", + "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", + "dev": true, + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "create-jest": "^29.7.0", + "exit": "^0.1.2", + "import-local": "^3.0.2", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "yargs": "^17.3.1" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-config": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz", + "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-jest": "^29.7.0", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@types/node": "*", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-dev-server": { + "version": "10.1.4", + "resolved": "https://registry.npmjs.org/jest-dev-server/-/jest-dev-server-10.1.4.tgz", + "integrity": "sha512-bGQ6sedNGtT6AFHhCVqGTXMPz7UyJi/ZrhNBgyqsP0XU9N8acCEIfqZEA22rOaZ+NdEVsaltk6tL7UT6aXfI7w==", + "dev": true, + "dependencies": { + "chalk": "^4.1.2", + "cwd": "^0.10.0", + "find-process": "^1.4.7", + "prompts": "^2.4.2", + "spawnd": "^10.1.4", + "tree-kill": "^1.2.2", + "wait-on": "^8.0.1" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-docblock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz", + "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==", + "dev": true, + "dependencies": { + "detect-newline": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-each": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz", + "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "jest-util": "^29.7.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-environment-jsdom": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-29.7.0.tgz", + "integrity": "sha512-k9iQbsf9OyOfdzWH8HDmrRT0gSIcX+FLNW7IQq94tFX0gynPwqDTW0Ho6iMVNjGz/nb+l/vW3dWM2bbLLpkbXA==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/jsdom": "^20.0.0", + "@types/node": "*", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0", + "jsdom": "^20.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "canvas": "^2.5.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jest-environment-node": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", + "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", + "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-leak-detector": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", + "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", + "dev": true, + "dependencies": { + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-mock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "dev": true, + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", + "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "resolve": "^1.20.0", + "resolve.exports": "^2.0.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz", + "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==", + "dev": true, + "dependencies": { + "jest-regex-util": "^29.6.3", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz", + "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==", + "dev": true, + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/environment": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-leak-detector": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-resolve": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-util": "^29.7.0", + "jest-watcher": "^29.7.0", + "jest-worker": "^29.7.0", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz", + "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/globals": "^29.7.0", + "@jest/source-map": "^29.6.3", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", + "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-jsx": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "natural-compare": "^1.4.0", + "pretty-format": "^29.7.0", + "semver": "^7.5.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/semver": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz", + "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", + "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "leven": "^3.1.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-watcher": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz", + "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==", + "dev": true, + "dependencies": { + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "jest-util": "^29.7.0", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", + "dev": true, + "dependencies": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/joi": { + "version": "18.2.1", + "resolved": "https://registry.npmjs.org/joi/-/joi-18.2.1.tgz", + "integrity": "sha512-2/OKlogiESf2Nh3TFCrRjrr9z1DRHeW0I+KReF67+4J0Ns+8hBtHRmoWAZ2OFU6I5+TWLEe6sVlSdXPjHm5UbQ==", + "dev": true, + "dependencies": { + "@hapi/address": "^5.1.1", + "@hapi/formula": "^3.0.2", + "@hapi/hoek": "^11.0.7", + "@hapi/pinpoint": "^2.0.1", + "@hapi/tlds": "^1.1.1", + "@hapi/topo": "^6.0.2", + "@standard-schema/spec": "^1.1.0" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/jpeg-js": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.4.4.tgz", + "integrity": "sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg==", + "dev": true + }, + "node_modules/js-library-detector": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/js-library-detector/-/js-library-detector-6.7.0.tgz", + "integrity": "sha512-c80Qupofp43y4cJ7+8TTDN/AsDwLi5oOm/plBrWI+iQt485vKXCco+yVmOwEgdo9VOdsYTuV0UlTeetVPTriXA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/js-yaml": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", + "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsdoc-type-pratt-parser": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.0.0.tgz", + "integrity": "sha512-YtOli5Cmzy3q4dP26GraSOeAhqecewG04hoO8DY56CH4KJ9Fvv5qKWUCCo3HZob7esJQHCv6/+bnTy72xZZaVQ==", + "dev": true, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/jsdom": { + "version": "20.0.3", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-20.0.3.tgz", + "integrity": "sha512-SYhBvTh89tTfCD/CRdSOm13mOBa42iTaTyfyEWBdKcGdPxPtLFBXuHR8XHb33YNYaP+lLbmSvBTsnoesCNJEsQ==", + "dev": true, + "dependencies": { + "abab": "^2.0.6", + "acorn": "^8.8.1", + "acorn-globals": "^7.0.0", + "cssom": "^0.5.0", + "cssstyle": "^2.3.0", + "data-urls": "^3.0.2", + "decimal.js": "^10.4.2", + "domexception": "^4.0.0", + "escodegen": "^2.0.0", + "form-data": "^4.0.0", + "html-encoding-sniffer": "^3.0.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.1", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.2", + "parse5": "^7.1.1", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.1.2", + "w3c-xmlserializer": "^4.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^2.0.0", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^11.0.0", + "ws": "^8.11.0", + "xml-name-validator": "^4.0.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "canvas": "^2.5.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/json2php": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/json2php/-/json2php-0.0.9.tgz", + "integrity": "sha512-fQMYwvPsQt8hxRnCGyg1r2JVi6yL8Um0DIIawiKiMK9yhAAkcRNj5UsBWoaFvFzPpcWbgw9L6wzj+UMYA702Mw==", + "dev": true + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonc-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.0.0.tgz", + "integrity": "sha512-fQzRfAbIBnR0IQvftw9FJveWiHp72Fg20giDrHz6TdfB12UH/uue0D3hm57UB5KgAVuniLMCaS8P1IMj9NR7cA==", + "dev": true + }, + "node_modules/jsx-ast-utils": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", + "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "object.assign": "^4.1.4", + "object.values": "^1.1.6" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/klona": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz", + "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/known-css-properties": { + "version": "0.37.0", + "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.37.0.tgz", + "integrity": "sha512-JCDrsP4Z1Sb9JwG0aJ8Eo2r7k4Ou5MwmThS/6lcIe1ICyb7UBJKGRIUUdqc2ASdE/42lgz6zFUnzAIhtXnBVrQ==", + "dev": true + }, + "node_modules/language-subtag-registry": { + "version": "0.3.23", + "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz", + "integrity": "sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==", + "dev": true + }, + "node_modules/language-tags": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz", + "integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==", + "dev": true, + "dependencies": { + "language-subtag-registry": "^0.3.20" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/launch-editor": { + "version": "2.13.2", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.13.2.tgz", + "integrity": "sha512-4VVDnbOpLXy/s8rdRCSXb+zfMeFR0WlJWpET1iA9CQdlZDfwyLjUuGQzXU4VeOoey6AicSAluWan7Etga6Kcmg==", + "dev": true, + "dependencies": { + "picocolors": "^1.1.1", + "shell-quote": "^1.8.3" + } + }, + "node_modules/lazy-cache": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", + "integrity": "sha512-RE2g0b5VGZsOCFOCgP7omTRYFqydmZkBwl5oNnQ1lDYC57uyO9KqNnNVxT7COSHTxrRCWVcAVOcbjk+tvh/rgQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/legacy-javascript": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/legacy-javascript/-/legacy-javascript-0.0.1.tgz", + "integrity": "sha512-lPyntS4/aS7jpuvOlitZDFifBCb4W8L/3QU0PLbUTUj+zYah8rfVjYic88yG7ZKTxhS5h9iz7duT8oUXKszLhg==", + "dev": true + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lighthouse": { + "version": "12.8.2", + "resolved": "https://registry.npmjs.org/lighthouse/-/lighthouse-12.8.2.tgz", + "integrity": "sha512-+5SKYzVaTFj22MgoYDPNrP9tlD2/Ay7j3SxPSFD9FpPyVxGr4UtOQGKyrdZ7wCmcnBaFk0mCkPfARU3CsE0nvA==", + "dev": true, + "dependencies": { + "@paulirish/trace_engine": "0.0.59", + "@sentry/node": "^9.28.1", + "axe-core": "^4.10.3", + "chrome-launcher": "^1.2.0", + "configstore": "^7.0.0", + "csp_evaluator": "1.1.5", + "devtools-protocol": "0.0.1507524", + "enquirer": "^2.3.6", + "http-link-header": "^1.1.1", + "intl-messageformat": "^10.5.3", + "jpeg-js": "^0.4.4", + "js-library-detector": "^6.7.0", + "lighthouse-logger": "^2.0.2", + "lighthouse-stack-packs": "1.12.2", + "lodash-es": "^4.17.21", + "lookup-closest-locale": "6.2.0", + "metaviewport-parser": "0.3.0", + "open": "^8.4.0", + "parse-cache-control": "1.0.1", + "puppeteer-core": "^24.17.1", + "robots-parser": "^3.0.1", + "speedline-core": "^1.4.3", + "third-party-web": "^0.27.0", + "tldts-icann": "^7.0.12", + "ws": "^7.0.0", + "yargs": "^17.3.1", + "yargs-parser": "^21.0.0" + }, + "bin": { + "chrome-debug": "core/scripts/manual-chrome-launcher.js", + "lighthouse": "cli/index.js", + "smokehouse": "cli/test/smokehouse/frontends/smokehouse-bin.js" + }, + "engines": { + "node": ">=18.16" + } + }, + "node_modules/lighthouse-logger": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lighthouse-logger/-/lighthouse-logger-2.0.2.tgz", + "integrity": "sha512-vWl2+u5jgOQuZR55Z1WM0XDdrJT6mzMP8zHUct7xTlWhuQs+eV0g+QL0RQdFjT54zVmbhLCP8vIVpy1wGn/gCg==", + "dev": true, + "dependencies": { + "debug": "^4.4.1", + "marky": "^1.2.2" + } + }, + "node_modules/lighthouse-stack-packs": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/lighthouse-stack-packs/-/lighthouse-stack-packs-1.12.2.tgz", + "integrity": "sha512-Ug8feS/A+92TMTCK6yHYLwaFMuelK/hAKRMdldYkMNwv+d9PtWxjXEg6rwKtsUXTADajhdrhXyuNCJ5/sfmPFw==", + "dev": true + }, + "node_modules/lighthouse/node_modules/@puppeteer/browsers": { + "version": "2.13.2", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.13.2.tgz", + "integrity": "sha512-5EUZSUIc37H6aIXyWO0Z4y8NlF8NnjgmqeQgOGiswAU7pY0HOo16ho4+alIWmSfdZnjqBRawMsP3I5YqLSn6kw==", + "dev": true, + "dependencies": { + "debug": "^4.4.3", + "extract-zip": "^2.0.1", + "progress": "^2.0.3", + "proxy-agent": "^6.5.0", + "semver": "^7.7.4", + "tar-fs": "^3.1.1", + "yargs": "^17.7.2" + }, + "bin": { + "browsers": "lib/cjs/main-cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/lighthouse/node_modules/puppeteer-core": { + "version": "24.43.1", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-24.43.1.tgz", + "integrity": "sha512-T5ScUMAsmhdNbgDR41AGESYeS6V9MSgetkSnVhhW+gXvzC42VesKCn5ld87gAZDJ6vLHL9GkRvY9WtQWSnwFbw==", + "dev": true, + "dependencies": { + "@puppeteer/browsers": "2.13.2", + "chromium-bidi": "14.0.0", + "debug": "^4.4.3", + "devtools-protocol": "0.0.1608973", + "typed-query-selector": "^2.12.2", + "webdriver-bidi-protocol": "0.4.1", + "ws": "^8.20.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/lighthouse/node_modules/puppeteer-core/node_modules/chromium-bidi": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-14.0.0.tgz", + "integrity": "sha512-9gYlLtS6tStdRWzrtXaTMnqcM4dudNegMXJxkR0I/CXObHalYeYcAMPrL19eroNZHtJ8DQmu1E+ZNOYu/IXMXw==", + "dev": true, + "dependencies": { + "mitt": "^3.0.1", + "zod": "^3.24.1" + }, + "peerDependencies": { + "devtools-protocol": "*" + } + }, + "node_modules/lighthouse/node_modules/puppeteer-core/node_modules/devtools-protocol": { + "version": "0.0.1608973", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1608973.tgz", + "integrity": "sha512-Tpm17fxYzt+J7VrGdc1k8YdRqS3YV7se/M6KeemEqvUbq/n7At1rWVuXMxQgpWkdwSdIEKYbU//Bve+Shm4YNQ==", + "dev": true + }, + "node_modules/lighthouse/node_modules/puppeteer-core/node_modules/ws": { + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", + "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/lighthouse/node_modules/semver": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz", + "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/lighthouse/node_modules/ws": { + "version": "7.5.11", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.11.tgz", + "integrity": "sha512-zS54Oen9bITtp7kp2XM3AydrCIq1D+HwJOuH+c+e4LfpL/lotP5osijd+UoMnxwAam1GN8R4KtLAyIrIcBNpiA==", + "dev": true, + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/lighthouse/node_modules/zod": { + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "node_modules/linkify-it": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz", + "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==", + "dev": true, + "dependencies": { + "uc.micro": "^1.0.1" + } + }, + "node_modules/loader-runner": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.2.tgz", + "integrity": "sha512-DFEqQ3ihfS9blba08cLfYf1NRAIEm+dDjic073DRDc3/JspI/8wYmtDsHwd3+4hwvdxSK7PGaElfTmm0awWJ4w==", + "dev": true, + "engines": { + "node": ">=6.11.5" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", + "dev": true + }, + "node_modules/lodash-es": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.18.1.tgz", + "integrity": "sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==", + "dev": true + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "dev": true + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "dev": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", + "dev": true + }, + "node_modules/lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", + "dev": true + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/loglevel": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.9.2.tgz", + "integrity": "sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg==", + "dev": true, + "engines": { + "node": ">= 0.6.0" + }, + "funding": { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/loglevel" + } + }, + "node_modules/lookup-closest-locale": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/lookup-closest-locale/-/lookup-closest-locale-6.2.0.tgz", + "integrity": "sha512-/c2kL+Vnp1jnV6K6RpDTHK3dgg0Tu2VVp+elEiJpjfS1UyY7AjOYHohRug6wT0OpoX2qFgNORndE9RqesfVxWQ==", + "dev": true + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/lucide-react": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-1.16.0.tgz", + "integrity": "sha512-dYwyPzb4MEKpGUmNYk3WKWPnMrHs3FKM+q94kAnJrcDIqqn1hq2xY8scaS2ovsOCM5D51ey2gaRG3PBb1vgoYQ==", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz", + "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "dependencies": { + "tmpl": "1.0.5" + } + }, + "node_modules/map-obj": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", + "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/map-values": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-values/-/map-values-1.0.1.tgz", + "integrity": "sha512-BbShUnr5OartXJe1GeccAWtfro11hhgNJg6G9/UtWKjVGvV5U4C09cg5nk8JUevhXODaXY+hQ3xxMUKSs62ONQ==", + "dev": true + }, + "node_modules/markdown-it": { + "version": "12.3.2", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz", + "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1", + "entities": "~2.1.0", + "linkify-it": "^3.0.1", + "mdurl": "^1.0.1", + "uc.micro": "^1.0.5" + }, + "bin": { + "markdown-it": "bin/markdown-it.js" + } + }, + "node_modules/markdown-it/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/markdown-it/node_modules/entities": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", + "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==", + "dev": true, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/markdownlint": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/markdownlint/-/markdownlint-0.25.1.tgz", + "integrity": "sha512-AG7UkLzNa1fxiOv5B+owPsPhtM4D6DoODhsJgiaNg1xowXovrYgOnLqAgOOFQpWOlHFVQUzjMY5ypNNTeov92g==", + "dev": true, + "dependencies": { + "markdown-it": "12.3.2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/markdownlint-cli": { + "version": "0.31.1", + "resolved": "https://registry.npmjs.org/markdownlint-cli/-/markdownlint-cli-0.31.1.tgz", + "integrity": "sha512-keIOMwQn+Ch7MoBwA+TdkyVMuxAeZFEGmIIlvwgV0Z1TGS5MxPnRr29XCLhkNzCHU+uNKGjU+VEjLX+Z9kli6g==", + "dev": true, + "dependencies": { + "commander": "~9.0.0", + "get-stdin": "~9.0.0", + "glob": "~7.2.0", + "ignore": "~5.2.0", + "js-yaml": "^4.1.0", + "jsonc-parser": "~3.0.0", + "markdownlint": "~0.25.1", + "markdownlint-rule-helpers": "~0.16.0", + "minimatch": "~3.0.5", + "run-con": "~1.2.10" + }, + "bin": { + "markdownlint": "markdownlint.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/markdownlint-cli/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/markdownlint-cli/node_modules/brace-expansion": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/markdownlint-cli/node_modules/commander": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.0.0.tgz", + "integrity": "sha512-JJfP2saEKbQqvW+FI93OYUB4ByV5cizMpFMiiJI8xDbBvQvSkIk0VvQdn1CZ8mqAO8Loq2h0gYTYtDFUZUeERw==", + "dev": true, + "engines": { + "node": "^12.20.0 || >=14" + } + }, + "node_modules/markdownlint-cli/node_modules/ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/markdownlint-cli/node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/markdownlint-cli/node_modules/minimatch": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.8.tgz", + "integrity": "sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/markdownlint-rule-helpers": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/markdownlint-rule-helpers/-/markdownlint-rule-helpers-0.16.0.tgz", + "integrity": "sha512-oEacRUVeTJ5D5hW1UYd2qExYI0oELdYK72k1TKGvIeYJIbqQWAz476NAc7LNixSySUhcNl++d02DvX0ccDk9/w==", + "dev": true + }, + "node_modules/marky": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/marky/-/marky-1.3.0.tgz", + "integrity": "sha512-ocnPZQLNpvbedwTy9kNrQEsknEfgvcLMvOtz3sFeWApDq1MXH1TqkCIx58xlpESsfwQOnuBO9beyQuNGzVvuhQ==", + "dev": true + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mathml-tag-names": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz", + "integrity": "sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/mdn-data": { + "version": "2.27.1", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.27.1.tgz", + "integrity": "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==", + "dev": true + }, + "node_modules/mdurl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", + "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==", + "dev": true + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memfs": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", + "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "dev": true, + "dependencies": { + "fs-monkey": "^1.0.4" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/memize": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/memize/-/memize-2.1.1.tgz", + "integrity": "sha512-8Nl+i9S5D6KXnruM03Jgjb+LwSupvR13WBr4hJegaaEyobvowCVupi79y2WSiWvO1mzBWxPwEYE5feCe8vyA5w==" + }, + "node_modules/meow": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-9.0.0.tgz", + "integrity": "sha512-+obSblOQmRhcyBt62furQqRAQpNyWXo8BuQ5bN7dG8wmwQ+vwHKp/rCFD4CrTP8CsDQD1sjoZ94K417XEUk8IQ==", + "dev": true, + "dependencies": { + "@types/minimist": "^1.2.0", + "camelcase-keys": "^6.2.2", + "decamelize": "^1.2.0", + "decamelize-keys": "^1.1.0", + "hard-rejection": "^2.1.0", + "minimist-options": "4.1.0", + "normalize-package-data": "^3.0.0", + "read-pkg-up": "^7.0.1", + "redent": "^3.0.0", + "trim-newlines": "^3.0.0", + "type-fest": "^0.18.0", + "yargs-parser": "^20.2.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/meow/node_modules/type-fest": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz", + "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/meow/node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/merge-deep": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/merge-deep/-/merge-deep-3.0.3.tgz", + "integrity": "sha512-qtmzAS6t6grwEkNrunqTBdn0qKwFgNWvlxUbAV8es9M7Ot1EbyApytCnvE0jALPa46ZpKDUo527kKiaWplmlFA==", + "dev": true, + "dependencies": { + "arr-union": "^3.1.0", + "clone-deep": "^0.2.4", + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/metaviewport-parser": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/metaviewport-parser/-/metaviewport-parser-0.3.0.tgz", + "integrity": "sha512-EoYJ8xfjQ6kpe9VbVHvZTZHiOl4HL1Z18CrZ+qahvLXT7ZO4YTC2JMyt5FaUp9JJp6J4Ybb/z7IsCXZt86/QkQ==", + "dev": true + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", + "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/mini-css-extract-plugin": { + "version": "2.10.2", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.10.2.tgz", + "integrity": "sha512-AOSS0IdEB95ayVkxn5oGzNQwqAi2J0Jb/kKm43t7H73s8+f5873g0yuj0PNvK4dO75mu5DHg4nlgp4k6Kga8eg==", + "dev": true, + "dependencies": { + "schema-utils": "^4.0.0", + "tapable": "^2.2.1" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minimist-options": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", + "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", + "dev": true, + "dependencies": { + "arrify": "^1.0.1", + "is-plain-obj": "^1.1.0", + "kind-of": "^6.0.3" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/minimist-options/node_modules/is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/minimist-options/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mitt": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", + "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", + "dev": true + }, + "node_modules/mixin-object": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mixin-object/-/mixin-object-2.0.1.tgz", + "integrity": "sha512-ALGF1Jt9ouehcaXaHhn6t1yGWRqGaHkPFndtFVHfZXOvkIZ/yoGaSi0AHVTafb3ZBGg4dr/bDwnaEKqCXzchMA==", + "dev": true, + "dependencies": { + "for-in": "^0.1.3", + "is-extendable": "^0.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mixin-object/node_modules/for-in": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-0.1.8.tgz", + "integrity": "sha512-F0to7vbBSHP8E3l6dCjxNOLuSFAACIxFy3UehTUlG7svlXi37HHsDkyVcHo0Pq8QwrE+pXvWSVX3ZT1T9wAZ9g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/module-details-from-path": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/module-details-from-path/-/module-details-from-path-1.0.4.tgz", + "integrity": "sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w==", + "dev": true + }, + "node_modules/mrmime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", + "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/multicast-dns": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", + "dev": true, + "dependencies": { + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" + }, + "bin": { + "multicast-dns": "cli.js" + } + }, + "node_modules/nanoid": { + "version": "3.3.12", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", + "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/napi-postinstall": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.4.tgz", + "integrity": "sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==", + "dev": true, + "bin": { + "napi-postinstall": "lib/cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/napi-postinstall" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/negotiator": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", + "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "node_modules/netmask": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.1.1.tgz", + "integrity": "sha512-eonl3sLUha+S1GzTPxychyhnUzKyeQkZ7jLjKrBagJgPla13F+uQ71HgpFefyHgqrjEbCPkDArxYsjY8/+gLKA==", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "dependencies": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, + "node_modules/node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "dev": true, + "optional": true + }, + "node_modules/node-exports-info": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/node-exports-info/-/node-exports-info-1.6.0.tgz", + "integrity": "sha512-pyFS63ptit/P5WqUkt+UUfe+4oevH+bFeIiPPdfb0pFeYEu/1ELnJu5l+5EcTKYL5M7zaAa7S8ddywgXypqKCw==", + "dev": true, + "dependencies": { + "array.prototype.flatmap": "^1.3.3", + "es-errors": "^1.3.0", + "object.entries": "^1.1.9", + "semver": "^6.3.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/node-forge": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.4.0.tgz", + "integrity": "sha512-LarFH0+6VfriEhqMMcLX2F7SwSXeWwnEAJEsYm5QKWchiVYVvJyV9v7UDvUv+w5HO23ZpQTXDv/GxdDdMyOuoQ==", + "dev": true, + "engines": { + "node": ">= 6.13.0" + } + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true + }, + "node_modules/node-releases": { + "version": "2.0.46", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.46.tgz", + "integrity": "sha512-GYVXHE2KnrzAfsAjl4uP++evGFCrAU1jta4ubEjIG7YWt/64Gqv66a30yKwWczVjA6j3bM4nBwH7Pk1JmDHaxQ==", + "dev": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/normalize-package-data": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", + "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^4.0.1", + "is-core-module": "^2.5.0", + "semver": "^7.3.4", + "validate-npm-package-license": "^3.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/normalize-package-data/node_modules/semver": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz", + "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-bundled": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.2.tgz", + "integrity": "sha512-x5DHup0SuyQcmL3s7Rx/YQ8sbw/Hzg0rj48eN0dV7hf5cmQq5PXIeioroH3raV1QC1yh3uTYuMThvEQF3iKgGQ==", + "dev": true, + "dependencies": { + "npm-normalize-package-bin": "^1.0.1" + } + }, + "node_modules/npm-normalize-package-bin": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", + "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==", + "dev": true + }, + "node_modules/npm-package-json-lint": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/npm-package-json-lint/-/npm-package-json-lint-6.4.0.tgz", + "integrity": "sha512-cuXAJJB1Rdqz0UO6w524matlBqDBjcNt7Ru+RDIu4y6RI1gVqiWBnylrK8sPRk81gGBA0X8hJbDXolVOoTc+sA==", + "dev": true, + "dependencies": { + "ajv": "^6.12.6", + "ajv-errors": "^1.0.1", + "chalk": "^4.1.2", + "cosmiconfig": "^8.0.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "ignore": "^5.2.0", + "is-plain-obj": "^3.0.0", + "jsonc-parser": "^3.2.0", + "log-symbols": "^4.1.0", + "meow": "^9.0.0", + "plur": "^4.0.0", + "semver": "^7.3.8", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1", + "type-fest": "^3.2.0", + "validate-npm-package-name": "^5.0.0" + }, + "bin": { + "npmPkgJsonLint": "dist/cli.js" + }, + "engines": { + "node": ">=14.0.0", + "npm": ">=6.0.0" + } + }, + "node_modules/npm-package-json-lint/node_modules/jsonc-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", + "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", + "dev": true + }, + "node_modules/npm-package-json-lint/node_modules/semver": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz", + "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm-package-json-lint/node_modules/type-fest": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-3.13.1.tgz", + "integrity": "sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==", + "dev": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-packlist": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-3.0.0.tgz", + "integrity": "sha512-L/cbzmutAwII5glUcf2DBRNY/d0TFd4e/FnaZigJV6JD85RHZXJFGwCndjMWiiViiWSsWt3tiOLpI3ByTnIdFQ==", + "dev": true, + "dependencies": { + "glob": "^7.1.6", + "ignore-walk": "^4.0.1", + "npm-bundled": "^1.1.1", + "npm-normalize-package-bin": "^1.0.1" + }, + "bin": { + "npm-packlist": "bin/index.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/nwsapi": { + "version": "2.2.23", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.23.tgz", + "integrity": "sha512-7wfH4sLbt4M0gCDzGE6vzQBo0bfTKjU7Sfpqy/7gs1qBfYz2vEJH6vXcBKpO3+6Yu1telwd0t9HpyOoLEQQbIQ==", + "dev": true + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-filter": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/object-filter/-/object-filter-1.0.2.tgz", + "integrity": "sha512-NahvP2vZcy1ZiiYah30CEPw0FpDcSkSePJBMpzl5EQgCmISijiGuJm3SPYp7U+Lf2TljyaIw3E5EgkEx/TNEVA==", + "dev": true + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.9.tgz", + "integrity": "sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.groupby": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", + "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.values": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz", + "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "dev": true + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz", + "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "dev": true, + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/opener": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", + "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", + "dev": true, + "bin": { + "opener": "bin/opener-bin.js" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/own-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", + "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.6", + "object-keys": "^1.1.1", + "safe-push-apply": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-locate/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "dev": true, + "dependencies": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pac-proxy-agent": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.2.0.tgz", + "integrity": "sha512-TEB8ESquiLMc0lV8vcd5Ql/JAKAoyzHFXaStwjkzpOpC5Yv+pIzLfHvjTSdf3vpa2bMiUQrg9i6276yn8666aA==", + "dev": true, + "dependencies": { + "@tootallnate/quickjs-emscripten": "^0.23.0", + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "get-uri": "^6.0.1", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.6", + "pac-resolver": "^7.0.1", + "socks-proxy-agent": "^8.0.5" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/pac-proxy-agent/node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "engines": { + "node": ">= 14" + } + }, + "node_modules/pac-proxy-agent/node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/pac-proxy-agent/node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dev": true, + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/pac-resolver": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz", + "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==", + "dev": true, + "dependencies": { + "degenerator": "^5.0.0", + "netmask": "^2.0.2" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/param-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", + "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-cache-control": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-cache-control/-/parse-cache-control-1.0.1.tgz", + "integrity": "sha512-60zvsJReQPX5/QP0Kzfd/VrpjScIQ7SHBW6bFCYfEP+fp0Eppr1SHhIO5nd1PjZtvclzSzES9D/p5nFJurwfWg==", + "dev": true + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse-passwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/parse5": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", + "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", + "dev": true, + "dependencies": { + "entities": "^6.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5/node_modules/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "dev": true, + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/path-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/path-case/-/path-case-3.0.4.tgz", + "integrity": "sha512-qO4qCFjXqVTrcbPt/hQfhTQ+VhFsqNKOPtytgNKkKxSoEp3XPUQ8ObFuePylOIok5gjn69ry8XiULxCwot3Wfg==", + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-to-regexp": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.13.tgz", + "integrity": "sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA==", + "dev": true + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "dev": true + }, + "node_modules/pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", + "dev": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/pg-protocol": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.14.0.tgz", + "integrity": "sha512-n5taZ1kO3s9ngDTVxsEznOqCyToTgz0FLuPq0B33COy5pPpuWJpY3/2oRBVETuOgzdqRXfWpM9HIhp2LBBT1BA==", + "dev": true + }, + "node_modules/pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "dev": true, + "dependencies": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pirates": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-7.0.0.tgz", + "integrity": "sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA==", + "dev": true, + "dependencies": { + "find-up": "^6.3.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", + "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", + "dev": true, + "dependencies": { + "locate-path": "^7.1.0", + "path-exists": "^5.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", + "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", + "dev": true, + "dependencies": { + "p-locate": "^6.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^1.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", + "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", + "dev": true, + "dependencies": { + "p-limit": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/path-exists": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", + "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/pkg-dir/node_modules/yocto-queue": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.2.tgz", + "integrity": "sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==", + "dev": true, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/playwright": { + "version": "1.60.0", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.60.0.tgz", + "integrity": "sha512-hheHdokM8cdqCb0lcE3s+zT4t4W+vvjpGxsZlDnikarzx8tSzMebh3UiFtgqwFwnTnjYQcsyMF8ei2mCO/tpeA==", + "dev": true, + "peer": true, + "dependencies": { + "playwright-core": "1.60.0" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.60.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.60.0.tgz", + "integrity": "sha512-9bW6zvX/m0lEbgTKJ6YppOKx8H3VOPBMOCFh2irXFOT4BbHgrx5hPjwJYLT40Lu+4qtD36qKc/Hn56StUW57IA==", + "dev": true, + "peer": true, + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/playwright/node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/plur": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/plur/-/plur-4.0.0.tgz", + "integrity": "sha512-4UGewrYgqDFw9vV6zNV+ADmPAUAfJPKtGvb/VdpQAx25X5f3xXdGdyOEVFwkl8Hl/tl7+xbeHqSEM+D5/TirUg==", + "dev": true, + "dependencies": { + "irregular-plurals": "^3.2.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/postcss": { + "version": "8.5.15", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", + "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.12", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-calc": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-9.0.1.tgz", + "integrity": "sha512-TipgjGyzP5QzEhsOZUaIkeO5mKeMFpebWzRogWG/ysonUlnHcq5aJe0jOjpfzUU8PeSaBQnrE8ehR0QA5vs8PQ==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.11", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.2.2" + } + }, + "node_modules/postcss-colormin": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-6.1.0.tgz", + "integrity": "sha512-x9yX7DOxeMAR+BgGVnNSAxmAj98NX/YxEMNFP+SDCEeNLb2r3i6Hh1ksMsnW8Ub5SLCpbescQqn9YEbE9554Sw==", + "dev": true, + "dependencies": { + "browserslist": "^4.23.0", + "caniuse-api": "^3.0.0", + "colord": "^2.9.3", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-convert-values": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-6.1.0.tgz", + "integrity": "sha512-zx8IwP/ts9WvUM6NkVSkiU902QZL1bwPhaVaLynPtCsOTqp+ZKbNi+s6XJg3rfqpKGA/oc7Oxk5t8pOQJcwl/w==", + "dev": true, + "dependencies": { + "browserslist": "^4.23.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-discard-comments": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-6.0.2.tgz", + "integrity": "sha512-65w/uIqhSBBfQmYnG92FO1mWZjJ4GL5b8atm5Yw2UgrwD7HiNiSSNwJor1eCFGzUgYnN/iIknhNRVqjrrpuglw==", + "dev": true, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-discard-duplicates": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-6.0.3.tgz", + "integrity": "sha512-+JA0DCvc5XvFAxwx6f/e68gQu/7Z9ud584VLmcgto28eB8FqSFZwtrLwB5Kcp70eIoWP/HXqz4wpo8rD8gpsTw==", + "dev": true, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-discard-empty": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-6.0.3.tgz", + "integrity": "sha512-znyno9cHKQsK6PtxL5D19Fj9uwSzC2mB74cpT66fhgOadEUPyXFkbgwm5tvc3bt3NAy8ltE5MrghxovZRVnOjQ==", + "dev": true, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-discard-overridden": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-6.0.2.tgz", + "integrity": "sha512-j87xzI4LUggC5zND7KdjsI25APtyMuynXZSujByMaav2roV6OZX+8AaCUcZSWqckZpjAjRyFDdpqybgjFO0HJQ==", + "dev": true, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-import": { + "version": "16.1.1", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-16.1.1.tgz", + "integrity": "sha512-2xVS1NCZAfjtVdvXiyegxzJ447GyqCeEI5V7ApgQVOWnros1p5lGNovJNapwPpMombyFBfqDwt7AD3n2l0KOfQ==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-loader": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-6.2.1.tgz", + "integrity": "sha512-WbbYpmAaKcux/P66bZ40bpWsBucjx/TTgVVzRZ9yUO8yQfVBlameJ0ZGVaPfH64hNSBh63a+ICP5nqOpBA0w+Q==", + "dev": true, + "dependencies": { + "cosmiconfig": "^7.0.0", + "klona": "^2.0.5", + "semver": "^7.3.5" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "postcss": "^7.0.0 || ^8.0.1", + "webpack": "^5.0.0" + } + }, + "node_modules/postcss-loader/node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "dev": true, + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/postcss-loader/node_modules/semver": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz", + "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/postcss-media-query-parser": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz", + "integrity": "sha512-3sOlxmbKcSHMjlUXQZKQ06jOswE7oVkXPxmZdoB1r5l0q6gTFTQSHxNxOrCccElbW7dxNytifNEo8qidX2Vsig==", + "dev": true + }, + "node_modules/postcss-merge-longhand": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-6.0.5.tgz", + "integrity": "sha512-5LOiordeTfi64QhICp07nzzuTDjNSO8g5Ksdibt44d+uvIIAE1oZdRn8y/W5ZtYgRH/lnLDlvi9F8btZcVzu3w==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0", + "stylehacks": "^6.1.1" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-merge-rules": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-6.1.1.tgz", + "integrity": "sha512-KOdWF0gju31AQPZiD+2Ar9Qjowz1LTChSjFFbS+e2sFgc4uHOp3ZvVX4sNeTlk0w2O31ecFGgrFzhO0RSWbWwQ==", + "dev": true, + "dependencies": { + "browserslist": "^4.23.0", + "caniuse-api": "^3.0.0", + "cssnano-utils": "^4.0.2", + "postcss-selector-parser": "^6.0.16" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-minify-font-values": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-6.1.0.tgz", + "integrity": "sha512-gklfI/n+9rTh8nYaSJXlCo3nOKqMNkxuGpTn/Qm0gstL3ywTr9/WRKznE+oy6fvfolH6dF+QM4nCo8yPLdvGJg==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-minify-gradients": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-6.0.3.tgz", + "integrity": "sha512-4KXAHrYlzF0Rr7uc4VrfwDJ2ajrtNEpNEuLxFgwkhFZ56/7gaE4Nr49nLsQDZyUe+ds+kEhf+YAUolJiYXF8+Q==", + "dev": true, + "dependencies": { + "colord": "^2.9.3", + "cssnano-utils": "^4.0.2", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-minify-params": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-6.1.0.tgz", + "integrity": "sha512-bmSKnDtyyE8ujHQK0RQJDIKhQ20Jq1LYiez54WiaOoBtcSuflfK3Nm596LvbtlFcpipMjgClQGyGr7GAs+H1uA==", + "dev": true, + "dependencies": { + "browserslist": "^4.23.0", + "cssnano-utils": "^4.0.2", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-minify-selectors": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-6.0.4.tgz", + "integrity": "sha512-L8dZSwNLgK7pjTto9PzWRoMbnLq5vsZSTu8+j1P/2GB8qdtGQfn+K1uSvFgYvgh83cbyxT5m43ZZhUMTJDSClQ==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.16" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-modules-extract-imports": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz", + "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-local-by-default": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.2.0.tgz", + "integrity": "sha512-5kcJm/zk+GJDSfw+V/42fJ5fhjL5YbFDl8nVdXkJPLLW+Vf9mTD5Xe0wqIaDnLuL2U6cDNpTr+UQ+v2HWIBhzw==", + "dev": true, + "dependencies": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^7.0.0", + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-local-by-default/node_modules/postcss-selector-parser": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-modules-scope": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.1.tgz", + "integrity": "sha512-m9jZstCVaqGjTAuny8MdgE88scJnCiQSlSrOWcTQgM2t32UBe+MUmFSO5t7VMSfAf/FJKImAxBav8ooCHJXCJA==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-scope/node_modules/postcss-selector-parser": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "dev": true, + "dependencies": { + "icss-utils": "^5.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-normalize-charset": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-6.0.2.tgz", + "integrity": "sha512-a8N9czmdnrjPHa3DeFlwqst5eaL5W8jYu3EBbTTkI5FHkfMhFZh1EGbku6jhHhIzTA6tquI2P42NtZ59M/H/kQ==", + "dev": true, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-display-values": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-6.0.2.tgz", + "integrity": "sha512-8H04Mxsb82ON/aAkPeq8kcBbAtI5Q2a64X/mnRRfPXBq7XeogoQvReqxEfc0B4WPq1KimjezNC8flUtC3Qz6jg==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-positions": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-6.0.2.tgz", + "integrity": "sha512-/JFzI441OAB9O7VnLA+RtSNZvQ0NCFZDOtp6QPFo1iIyawyXg0YI3CYM9HBy1WvwCRHnPep/BvI1+dGPKoXx/Q==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-repeat-style": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-6.0.2.tgz", + "integrity": "sha512-YdCgsfHkJ2jEXwR4RR3Tm/iOxSfdRt7jplS6XRh9Js9PyCR/aka/FCb6TuHT2U8gQubbm/mPmF6L7FY9d79VwQ==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-string": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-6.0.2.tgz", + "integrity": "sha512-vQZIivlxlfqqMp4L9PZsFE4YUkWniziKjQWUtsxUiVsSSPelQydwS8Wwcuw0+83ZjPWNTl02oxlIvXsmmG+CiQ==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-timing-functions": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-6.0.2.tgz", + "integrity": "sha512-a+YrtMox4TBtId/AEwbA03VcJgtyW4dGBizPl7e88cTFULYsprgHWTbfyjSLyHeBcK/Q9JhXkt2ZXiwaVHoMzA==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-unicode": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-6.1.0.tgz", + "integrity": "sha512-QVC5TQHsVj33otj8/JD869Ndr5Xcc/+fwRh4HAsFsAeygQQXm+0PySrKbr/8tkDKzW+EVT3QkqZMfFrGiossDg==", + "dev": true, + "dependencies": { + "browserslist": "^4.23.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-url": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-6.0.2.tgz", + "integrity": "sha512-kVNcWhCeKAzZ8B4pv/DnrU1wNh458zBNp8dh4y5hhxih5RZQ12QWMuQrDgPRw3LRl8mN9vOVfHl7uhvHYMoXsQ==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-whitespace": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-6.0.2.tgz", + "integrity": "sha512-sXZ2Nj1icbJOKmdjXVT9pnyHQKiSAyuNQHSgRCUgThn2388Y9cGVDR+E9J9iAYbSbLHI+UUwLVl1Wzco/zgv0Q==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-ordered-values": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-6.0.2.tgz", + "integrity": "sha512-VRZSOB+JU32RsEAQrO94QPkClGPKJEL/Z9PCBImXMhIeK5KAYo6slP/hBYlLgrCjFxyqvn5VC81tycFEDBLG1Q==", + "dev": true, + "dependencies": { + "cssnano-utils": "^4.0.2", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-reduce-initial": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-6.1.0.tgz", + "integrity": "sha512-RarLgBK/CrL1qZags04oKbVbrrVK2wcxhvta3GCxrZO4zveibqbRPmm2VI8sSgCXwoUHEliRSbOfpR0b/VIoiw==", + "dev": true, + "dependencies": { + "browserslist": "^4.23.0", + "caniuse-api": "^3.0.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-reduce-transforms": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-6.0.2.tgz", + "integrity": "sha512-sB+Ya++3Xj1WaT9+5LOOdirAxP7dJZms3GRcYheSPi1PiTMigsxHAdkrbItHxwYHr4kt1zL7mmcHstgMYT+aiA==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-resolve-nested-selector": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/postcss-resolve-nested-selector/-/postcss-resolve-nested-selector-0.1.6.tgz", + "integrity": "sha512-0sglIs9Wmkzbr8lQwEyIzlDOOC9bGmfVKcJTaxv3vMmd3uo4o4DerC3En0bnmgceeql9BfC8hRkp7cg0fjdVqw==", + "dev": true + }, + "node_modules/postcss-safe-parser": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-7.0.1.tgz", + "integrity": "sha512-0AioNCJZ2DPYz5ABT6bddIqlhgwhpHZ/l65YAYo0BCIn0xiDpsnTHz0gnoTGk0OXZW0JRs+cDwL8u/teRdz+8A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss-safe-parser" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-scss": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/postcss-scss/-/postcss-scss-4.0.9.tgz", + "integrity": "sha512-AjKOeiwAitL/MXxQW2DliT28EKukvvbEWx3LBmJIRN8KfBGZbRTxNYW0kSqi1COiTZ57nZ9NW06S6ux//N1c9A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss-scss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "engines": { + "node": ">=12.0" + }, + "peerDependencies": { + "postcss": "^8.4.29" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-svgo": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-6.0.3.tgz", + "integrity": "sha512-dlrahRmxP22bX6iKEjOM+c8/1p+81asjKT+V5lrgOH944ryx/OHpclnIbGsKVd3uWOXFLYJwCVf0eEkJGvO96g==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0", + "svgo": "^3.2.0" + }, + "engines": { + "node": "^14 || ^16 || >= 18" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-unique-selectors": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-6.0.4.tgz", + "integrity": "sha512-K38OCaIrO8+PzpArzkLKB42dSARtC2tmG6PvD4b1o1Q2E9Os8jzfWFfSy/rixsHwohtsDdFtAWGjFVFUdwYaMg==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.16" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true + }, + "node_modules/postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/postgres-bytea": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.1.tgz", + "integrity": "sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-date": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "dev": true, + "dependencies": { + "xtend": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "name": "wp-prettier", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/wp-prettier/-/wp-prettier-3.0.3.tgz", + "integrity": "sha512-X4UlrxDTH8oom9qXlcjnydsjAOD2BmB6yFmvS4Z2zdTzqqpRWb+fbqrH412+l+OUXmbzJlSXjlMFYPgYG12IAA==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.1.tgz", + "integrity": "sha512-SxToR7P8Y2lWmv/kTzVLC1t/GDI2WGjMwNhLLE9qtH8Q13C+aEmuRlzDst4Up4s0Wc8sF2M+J57iB3cMLqftfg==", + "dev": true, + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dev": true, + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dev": true, + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-addr/node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-agent": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.5.0.tgz", + "integrity": "sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A==", + "dev": true, + "dependencies": { + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "http-proxy-agent": "^7.0.1", + "https-proxy-agent": "^7.0.6", + "lru-cache": "^7.14.1", + "pac-proxy-agent": "^7.1.0", + "proxy-from-env": "^1.1.0", + "socks-proxy-agent": "^8.0.5" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/proxy-agent/node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "engines": { + "node": ">= 14" + } + }, + "node_modules/proxy-agent/node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/proxy-agent/node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dev": true, + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/proxy-agent/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "dev": true + }, + "node_modules/psl": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz", + "integrity": "sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==", + "dev": true, + "dependencies": { + "punycode": "^2.3.1" + }, + "funding": { + "url": "https://github.com/sponsors/lupomontero" + } + }, + "node_modules/pump": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", + "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/puppeteer-core": { + "version": "23.11.1", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-23.11.1.tgz", + "integrity": "sha512-3HZ2/7hdDKZvZQ7dhhITOUg4/wOrDRjyK2ZBllRB0ZCOi9u0cwq1ACHDjBB+nX+7+kltHjQvBRdeY7+W0T+7Gg==", + "dev": true, + "dependencies": { + "@puppeteer/browsers": "2.6.1", + "chromium-bidi": "0.11.0", + "debug": "^4.4.0", + "devtools-protocol": "0.0.1367902", + "typed-query-selector": "^2.12.0", + "ws": "^8.18.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/puppeteer-core/node_modules/devtools-protocol": { + "version": "0.0.1367902", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1367902.tgz", + "integrity": "sha512-XxtPuC3PGakY6PD7dG66/o8KwJ/LkH2/EKe19Dcw58w53dv4/vSQEkn/SzuyhHE2q4zPgCkxQBxus3VV4ql+Pg==", + "dev": true + }, + "node_modules/pure-rand": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", + "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ] + }, + "node_modules/qified": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/qified/-/qified-0.10.1.tgz", + "integrity": "sha512-+Owyggi9IxT1ePKGafcI87ubSmxol6smwJ+RAHDQlx9+9cPwFWDiKFFCPuWhr9ignlGpZ9vDQLw67N4dcTVFEA==", + "dev": true, + "dependencies": { + "hookified": "^2.1.1" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/qified/node_modules/hookified": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/hookified/-/hookified-2.2.0.tgz", + "integrity": "sha512-p/LgFzRN5FeoD3DLS6bkUapeye6E4SI6yJs6KetENd18S+FBthqYq2amJUWpt5z0EQwwHemidjY5OqJGEKm5uA==", + "dev": true + }, + "node_modules/qs": { + "version": "6.15.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.2.tgz", + "integrity": "sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==", + "dev": true, + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "dev": true + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/quick-lru": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", + "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz", + "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", + "dev": true, + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/raw-body/node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true + }, + "node_modules/react-refresh": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz", + "integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "dev": true, + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "dev": true, + "dependencies": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "dev": true, + "dependencies": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg-up/node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg/node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "node_modules/read-pkg/node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/read-pkg/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/read-pkg/node_modules/type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", + "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", + "dev": true, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/rechoir": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", + "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", + "dev": true, + "dependencies": { + "resolve": "^1.20.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dev": true, + "dependencies": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", + "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.1", + "which-builtin-type": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.2.tgz", + "integrity": "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g==", + "dev": true, + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", + "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexpu-core": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.4.0.tgz", + "integrity": "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA==", + "dev": true, + "dependencies": { + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.2.2", + "regjsgen": "^0.8.0", + "regjsparser": "^0.13.0", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.2.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", + "dev": true + }, + "node_modules/regjsparser": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.13.1.tgz", + "integrity": "sha512-dLsljMd9sqwRkby8zhO1gSg3PnJIBFid8f4CQj/sXx+7cKx+E7u0PKhZ+U4wmhx7EfmtvnA318oVaIkAB1lRJw==", + "dev": true, + "dependencies": { + "jsesc": "~3.1.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/remove-accents": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/remove-accents/-/remove-accents-0.5.0.tgz", + "integrity": "sha512-8g3/Otx1eJaVD12e31UbJj1YzdtVvzH85HV7t+9MJYk/u3XmkOUJ5Ys9wQrf9PCPK8+xn4ymzqYCiZl6QWKn+A==" + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-in-the-middle": { + "version": "7.5.2", + "resolved": "https://registry.npmjs.org/require-in-the-middle/-/require-in-the-middle-7.5.2.tgz", + "integrity": "sha512-gAZ+kLqBdHarXB64XpAe2VCjB7rIRv+mU8tfRWziHRJ5umKsIHN2tLLv6EtMw7WCdP19S0ERVMldNvxYCHnhSQ==", + "dev": true, + "dependencies": { + "debug": "^4.3.5", + "module-details-from-path": "^1.0.3", + "resolve": "^1.22.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/requireindex": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/requireindex/-/requireindex-1.2.0.tgz", + "integrity": "sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww==", + "dev": true, + "engines": { + "node": ">=0.10.5" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true + }, + "node_modules/resolve": { + "version": "1.22.12", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-bin": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/resolve-bin/-/resolve-bin-0.4.3.tgz", + "integrity": "sha512-9u8TMpc+SEHXxQXblXHz5yRvRZERkCZimFN9oz85QI3uhkh7nqfjm6OGTLg+8vucpXGcY4jLK6WkylPmt7GSvw==", + "dev": true, + "dependencies": { + "find-parent-dir": "~0.3.0" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-dir": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-0.1.1.tgz", + "integrity": "sha512-QxMPqI6le2u0dCLyiGzgy92kjkkL6zO0XyvHzjdTNH3zM6e5Hz3BwG6+aEyNgiQ5Xz6PwTwgQEj3U50dByPKIA==", + "dev": true, + "dependencies": { + "expand-tilde": "^1.2.2", + "global-modules": "^0.2.3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/resolve.exports": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.3.tgz", + "integrity": "sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/robots-parser": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/robots-parser/-/robots-parser-3.0.1.tgz", + "integrity": "sha512-s+pyvQeIKIZ0dx5iJiQk1tPLJAWln39+MI5jtM8wnyws+G5azk+dMnMX0qfbqNetKKNgcWWOdi0sfm+FbQbgdQ==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/rtlcss": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/rtlcss/-/rtlcss-4.3.0.tgz", + "integrity": "sha512-FI+pHEn7Wc4NqKXMXFM+VAYKEj/mRIcW4h24YVwVtyjI+EqGrLc2Hx/Ny0lrZ21cBWU2goLy36eqMcNj3AQJig==", + "dev": true, + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0", + "postcss": "^8.4.21", + "strip-json-comments": "^3.1.1" + }, + "bin": { + "rtlcss": "bin/rtlcss.js" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/run-con": { + "version": "1.2.12", + "resolved": "https://registry.npmjs.org/run-con/-/run-con-1.2.12.tgz", + "integrity": "sha512-5257ILMYIF4RztL9uoZ7V9Q97zHtNHn5bN3NobeAnzB1P3ASLgg8qocM2u+R18ttp+VEM78N2LK8XcNVtnSRrg==", + "dev": true, + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~3.0.0", + "minimist": "^1.2.8", + "strip-json-comments": "~3.1.1" + }, + "bin": { + "run-con": "cli.js" + } + }, + "node_modules/run-con/node_modules/ini": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ini/-/ini-3.0.1.tgz", + "integrity": "sha512-it4HyVAUTKBc6m8e1iXWvXSTdndF7HbdN713+kvLrymxTaU4AUBWrJ4vEooP+V7fexnVD3LKcBshjGGPefSMUQ==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rxjs": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "dev": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/safe-array-concat": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.4.tgz", + "integrity": "sha512-wtZlHyOje6OZTGqAoaDKxFkgRtkF9CnHAVnCHKfuj200wAgL+bSJhdsCD2l0Qx/2ekEXjPWcyKkfGb5CPboslg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.9", + "call-bound": "^1.0.4", + "get-intrinsic": "^1.3.0", + "has-symbols": "^1.1.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safe-push-apply": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", + "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "dev": true, + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/sass": { + "version": "1.100.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.100.0.tgz", + "integrity": "sha512-B5j0rYMlinhhOo9tjQebMVVn0TfyXAF+wB3b2ggZUuJ/is/Y+7+JGjirAMxHZ9Z3hIP98NPfamlAkBHa1lAaXQ==", + "dev": true, + "dependencies": { + "chokidar": "^5.0.0", + "immutable": "^5.1.5", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=20.19.0" + }, + "optionalDependencies": { + "@parcel/watcher": "^2.4.1" + } + }, + "node_modules/sass-loader": { + "version": "16.0.8", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-16.0.8.tgz", + "integrity": "sha512-hcov4ZwZJIGbEuyNr9EmiTmZueyrxSToE6GOzoZnq5JM7ecRO7ttyvilPn+VmRsqiP16+VYZzVnGZj/hzZgKBA==", + "dev": true, + "dependencies": { + "neo-async": "^2.6.2" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "@rspack/core": "0.x || ^1.0.0 || ^2.0.0-0", + "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0", + "sass": "^1.3.0", + "sass-embedded": "*", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "node-sass": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/sax": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.0.tgz", + "integrity": "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==", + "dev": true, + "engines": { + "node": ">=11.0.0" + } + }, + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "dev": true, + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/schema-utils": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", + "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/schema-utils/node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/schema-utils/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/schema-utils/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", + "dev": true + }, + "node_modules/selfsigned": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", + "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", + "dev": true, + "dependencies": { + "@types/node-forge": "^1.3.0", + "node-forge": "^1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/send": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz", + "integrity": "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.1", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "~2.4.1", + "range-parser": "~1.2.1", + "statuses": "~2.0.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/send/node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/sentence-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/sentence-case/-/sentence-case-3.0.4.tgz", + "integrity": "sha512-8LS0JInaQMCRoQ7YUytAo/xUu5W2XnQxV2HI/6uM6U7CITS1RqPElr30V6uIqyMKM9lJGRVFy5/4CuzcixNYSg==", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3", + "upper-case-first": "^2.0.2" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-index": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.2.tgz", + "integrity": "sha512-KDj11HScOaLmrPxl70KYNW1PksP4Nb/CLL2yvC+Qd2kHMPEEpfc4Re2e4FOay+bC/+XQl/7zAcWON3JVo5v3KQ==", + "dev": true, + "dependencies": { + "accepts": "~1.3.8", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.8.0", + "mime-types": "~2.1.35", + "parseurl": "~1.3.3" + }, + "engines": { + "node": ">= 0.8.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/serve-index/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/serve-index/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/http-errors": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", + "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", + "dev": true, + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/serve-index/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-static": { + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.3.tgz", + "integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==", + "dev": true, + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "~0.19.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-proto": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", + "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", + "dev": true, + "dependencies": { + "dunder-proto": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true + }, + "node_modules/shallow-clone": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-0.1.2.tgz", + "integrity": "sha512-J1zdXCky5GmNnuauESROVu31MQSnLoYvlyEn6j2Ztk6Q5EHFIhxkMhYcv6vuDzl2XEzoRr856QwzMgWM/TmZgw==", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.1", + "kind-of": "^2.0.1", + "lazy-cache": "^0.2.3", + "mixin-object": "^2.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/shallow-clone/node_modules/kind-of": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-2.0.1.tgz", + "integrity": "sha512-0u8i1NZ/mg0b+W3MGGw5I7+6Eib2nx72S/QvXa0hYjEkjTknYmEYQJwGu3mLC0BrhtJjtQafTkyRUQ75Kx0LVg==", + "dev": true, + "dependencies": { + "is-buffer": "^1.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/shallow-clone/node_modules/lazy-cache": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-0.2.7.tgz", + "integrity": "sha512-gkX52wvU/R8DVMMt78ATVPFMJqfW8FPz1GZ1sVHBVQHmu/WvhIWE4cE1GBzhJNFicDeYhnwp6Rl35BcAIM3YOQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.8.4", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.4.tgz", + "integrity": "sha512-VsC6n6vz1ihYYyZZwX7YZSF5l5x36ca17OC+a69h94YqB7X6XLwf+5MOgynYir2SLFUbl8gIYvBo8K8RoNQ6bQ==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/shimmer": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/shimmer/-/shimmer-1.2.1.tgz", + "integrity": "sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==", + "dev": true + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/sirv": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.4.tgz", + "integrity": "sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==", + "dev": true, + "dependencies": { + "@polka/url": "^1.0.0-next.24", + "mrmime": "^2.0.0", + "totalist": "^3.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true, + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/snake-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz", + "integrity": "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==", + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/sockjs": { + "version": "0.3.24", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", + "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "dev": true, + "dependencies": { + "faye-websocket": "^0.11.3", + "uuid": "^8.3.2", + "websocket-driver": "^0.7.4" + } + }, + "node_modules/socks": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.9.tgz", + "integrity": "sha512-LJhUYUvItdQ0LkJTmPeaEObWXAqFyfmP85x0tch/ez9cahmhlBBLbIqDFnvBnUJGagb0JbIQrkBs1wJ+yRYpEw==", + "dev": true, + "dependencies": { + "ip-address": "^10.1.1", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz", + "integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==", + "dev": true, + "dependencies": { + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "socks": "^2.8.3" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/socks-proxy-agent/node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "engines": { + "node": ">= 14" + } + }, + "node_modules/source-map": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", + "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", + "dev": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-loader": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-3.0.2.tgz", + "integrity": "sha512-BokxPoLjyl3iOrgkWaakaxqnelAJSS+0V+De0kKIq6lyWrXuiPgYTGp6z3iHmqljKAaLXwZa+ctD8GccRJeVvg==", + "dev": true, + "dependencies": { + "abab": "^2.0.5", + "iconv-lite": "^0.6.3", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/spawnd": { + "version": "10.1.4", + "resolved": "https://registry.npmjs.org/spawnd/-/spawnd-10.1.4.tgz", + "integrity": "sha512-drqHc0mKJmtMsiGMOCwzlc5eZ0RPtRvT7tQAluW2A0qUc0G7TQ8KLcn3E6K5qzkLkH2UkS3nYQiVGULvvsD9dw==", + "dev": true, + "dependencies": { + "signal-exit": "^4.1.0", + "tree-kill": "^1.2.2" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/spawnd/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dev": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-correct/node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "dev": true + }, + "node_modules/spdx-expression-parse": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz", + "integrity": "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.23", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.23.tgz", + "integrity": "sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw==", + "dev": true + }, + "node_modules/spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + } + }, + "node_modules/speedline-core": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/speedline-core/-/speedline-core-1.4.3.tgz", + "integrity": "sha512-DI7/OuAUD+GMpR6dmu8lliO2Wg5zfeh+/xsdyJZCzd8o5JgFUjCeLsBDuZjIQJdwXS3J0L/uZYrELKYqx+PXog==", + "dev": true, + "dependencies": { + "@types/node": "*", + "image-ssim": "^0.2.0", + "jpeg-js": "^0.4.1" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==" + }, + "node_modules/stable-hash-x": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/stable-hash-x/-/stable-hash-x-0.2.0.tgz", + "integrity": "sha512-o3yWv49B/o4QZk5ZcsALc6t0+eCelPc44zZsLtCQnZPDwFpDYSWcDnrv2TtMmMbQ7uKo3J0HTURCqckw23czNQ==", + "dev": true, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/stackframe": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz", + "integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==", + "dev": true + }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/stop-iteration-iterator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", + "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "internal-slot": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/streamx": { + "version": "2.25.0", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.25.0.tgz", + "integrity": "sha512-0nQuG6jf1w+wddNEEXCF4nTg3LtufWINB5eFEN+5TNZW7KWJp6x87+JFL43vaAUPyCfH1wID+mNVyW6OHtFamg==", + "dev": true, + "dependencies": { + "events-universal": "^1.0.0", + "fast-fifo": "^1.3.2", + "text-decoder": "^1.1.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/string.prototype.includes": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.1.tgz", + "integrity": "sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/string.prototype.matchall": { + "version": "4.0.12", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz", + "integrity": "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.6", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.6", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "internal-slot": "^1.1.0", + "regexp.prototype.flags": "^1.5.3", + "set-function-name": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.repeat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz", + "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.10", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", + "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-data-property": "^1.1.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-object-atoms": "^1.0.0", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", + "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-outer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz", + "integrity": "sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^1.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-outer/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/stubborn-fs": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/stubborn-fs/-/stubborn-fs-2.0.0.tgz", + "integrity": "sha512-Y0AvSwDw8y+nlSNFXMm2g6L51rBGdAQT20J3YSOqxC53Lo3bjWRtr2BKcfYoAf352WYpsZSTURrA0tqhfgudPA==", + "dev": true, + "dependencies": { + "stubborn-utils": "^1.0.1" + } + }, + "node_modules/stubborn-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/stubborn-utils/-/stubborn-utils-1.0.2.tgz", + "integrity": "sha512-zOh9jPYI+xrNOyisSelgym4tolKTJCQd5GBhK0+0xJvcYDcwlOoxF/rnFKQ2KRZknXSG9jWAp66fwP6AxN9STg==", + "dev": true + }, + "node_modules/style-search": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/style-search/-/style-search-0.1.0.tgz", + "integrity": "sha512-Dj1Okke1C3uKKwQcetra4jSuk0DqbzbYtXipzFlFMZtowbF1x7BKJwB9AayVMyFARvU8EDrZdcax4At/452cAg==", + "dev": true + }, + "node_modules/stylehacks": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-6.1.1.tgz", + "integrity": "sha512-gSTTEQ670cJNoaeIp9KX6lZmm8LJ3jPB5yJmX8Zq/wQxOsAFXV3qjWzHas3YYk1qesuVIyYWWUpZ0vSE/dTSGg==", + "dev": true, + "dependencies": { + "browserslist": "^4.23.0", + "postcss-selector-parser": "^6.0.16" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/stylelint": { + "version": "16.26.1", + "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.26.1.tgz", + "integrity": "sha512-v20V59/crfc8sVTAtge0mdafI3AdnzQ2KsWe6v523L4OA1bJO02S7MO2oyXDCS6iWb9ckIPnqAFVItqSBQr7jw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/stylelint" + }, + { + "type": "github", + "url": "https://github.com/sponsors/stylelint" + } + ], + "dependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-syntax-patches-for-csstree": "^1.0.19", + "@csstools/css-tokenizer": "^3.0.4", + "@csstools/media-query-list-parser": "^4.0.3", + "@csstools/selector-specificity": "^5.0.0", + "@dual-bundle/import-meta-resolve": "^4.2.1", + "balanced-match": "^2.0.0", + "colord": "^2.9.3", + "cosmiconfig": "^9.0.0", + "css-functions-list": "^3.2.3", + "css-tree": "^3.1.0", + "debug": "^4.4.3", + "fast-glob": "^3.3.3", + "fastest-levenshtein": "^1.0.16", + "file-entry-cache": "^11.1.1", + "global-modules": "^2.0.0", + "globby": "^11.1.0", + "globjoin": "^0.1.4", + "html-tags": "^3.3.1", + "ignore": "^7.0.5", + "imurmurhash": "^0.1.4", + "is-plain-object": "^5.0.0", + "known-css-properties": "^0.37.0", + "mathml-tag-names": "^2.1.3", + "meow": "^13.2.0", + "micromatch": "^4.0.8", + "normalize-path": "^3.0.0", + "picocolors": "^1.1.1", + "postcss": "^8.5.6", + "postcss-resolve-nested-selector": "^0.1.6", + "postcss-safe-parser": "^7.0.1", + "postcss-selector-parser": "^7.1.0", + "postcss-value-parser": "^4.2.0", + "resolve-from": "^5.0.0", + "string-width": "^4.2.3", + "supports-hyperlinks": "^3.2.0", + "svg-tags": "^1.0.0", + "table": "^6.9.0", + "write-file-atomic": "^5.0.1" + }, + "bin": { + "stylelint": "bin/stylelint.mjs" + }, + "engines": { + "node": ">=18.12.0" + } + }, + "node_modules/stylelint-config-recommended": { + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-14.0.1.tgz", + "integrity": "sha512-bLvc1WOz/14aPImu/cufKAZYfXs/A/owZfSMZ4N+16WGXLoX5lOir53M6odBxvhgmgdxCVnNySJmZKx73T93cg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/stylelint" + }, + { + "type": "github", + "url": "https://github.com/sponsors/stylelint" + } + ], + "engines": { + "node": ">=18.12.0" + }, + "peerDependencies": { + "stylelint": "^16.1.0" + } + }, + "node_modules/stylelint-config-recommended-scss": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/stylelint-config-recommended-scss/-/stylelint-config-recommended-scss-14.1.0.tgz", + "integrity": "sha512-bhaMhh1u5dQqSsf6ri2GVWWQW5iUjBYgcHkh7SgDDn92ijoItC/cfO/W+fpXshgTQWhwFkP1rVcewcv4jaftRg==", + "dev": true, + "dependencies": { + "postcss-scss": "^4.0.9", + "stylelint-config-recommended": "^14.0.1", + "stylelint-scss": "^6.4.0" + }, + "engines": { + "node": ">=18.12.0" + }, + "peerDependencies": { + "postcss": "^8.3.3", + "stylelint": "^16.6.1" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + } + } + }, + "node_modules/stylelint-scss": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/stylelint-scss/-/stylelint-scss-6.14.0.tgz", + "integrity": "sha512-ZKmHMZolxeuYsnB+PCYrTpFce0/QWX9i9gh0hPXzp73WjuIMqUpzdQaBCrKoLWh6XtCFSaNDErkMPqdjy1/8aA==", + "dev": true, + "dependencies": { + "css-tree": "^3.0.1", + "is-plain-object": "^5.0.0", + "known-css-properties": "^0.37.0", + "mdn-data": "^2.25.0", + "postcss-media-query-parser": "^0.2.3", + "postcss-resolve-nested-selector": "^0.1.6", + "postcss-selector-parser": "^7.1.1", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=18.12.0" + }, + "peerDependencies": { + "stylelint": "^16.8.2" + } + }, + "node_modules/stylelint-scss/node_modules/postcss-selector-parser": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/stylelint/node_modules/@csstools/media-query-list-parser": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-4.0.3.tgz", + "integrity": "sha512-HAYH7d3TLRHDOUQK4mZKf9k9Ph/m8Akstg66ywKR4SFAigjs3yBiUeZtFxywiTm5moZMAp/5W/ZuFnNXXYLuuQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/stylelint/node_modules/@csstools/selector-specificity": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-5.0.0.tgz", + "integrity": "sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "postcss-selector-parser": "^7.0.0" + } + }, + "node_modules/stylelint/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/stylelint/node_modules/balanced-match": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-2.0.0.tgz", + "integrity": "sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA==", + "dev": true + }, + "node_modules/stylelint/node_modules/cosmiconfig": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.1.tgz", + "integrity": "sha512-hr4ihw+DBqcvrsEDioRO31Z17x71pUYoNe/4h6Z0wB72p7MU7/9gH8Q3s12NFhHPfYBBOV3qyfUxmr/Yn3shnQ==", + "dev": true, + "dependencies": { + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/stylelint/node_modules/file-entry-cache": { + "version": "11.1.3", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-11.1.3.tgz", + "integrity": "sha512-oMbq0PD6VIiIwMF6LIa7MEwd/l9huKwmqRKXqmrkqIZv8CvRbfowL+L0ryAl8h//HfAS0zS+4SbYoRyAoA6BJA==", + "dev": true, + "dependencies": { + "flat-cache": "^6.1.22" + } + }, + "node_modules/stylelint/node_modules/flat-cache": { + "version": "6.1.22", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-6.1.22.tgz", + "integrity": "sha512-N2dnzVJIphnNsjHcrxGW7DePckJ6haPrSFqpsBUhHYgwtKGVq4JrBGielEGD2fCVnsGm1zlBVZ8wGhkyuetgug==", + "dev": true, + "dependencies": { + "cacheable": "^2.3.4", + "flatted": "^3.4.2", + "hookified": "^1.15.0" + } + }, + "node_modules/stylelint/node_modules/global-modules": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", + "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", + "dev": true, + "dependencies": { + "global-prefix": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/stylelint/node_modules/global-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", + "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", + "dev": true, + "dependencies": { + "ini": "^1.3.5", + "kind-of": "^6.0.2", + "which": "^1.3.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/stylelint/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/stylelint/node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/stylelint/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stylelint/node_modules/meow": { + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-13.2.0.tgz", + "integrity": "sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/stylelint/node_modules/postcss-selector-parser": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.1.tgz", + "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/stylelint/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/stylelint/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/stylelint/node_modules/write-file-atomic": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz", + "integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-hyperlinks": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-3.2.0.tgz", + "integrity": "sha512-zFObLMyZeEwzAoKCyu1B91U79K2t7ApXuQfo8OuxwXLDgcKxuwM+YvcbIhm6QWqz7mHUH1TVytR1PwVVjEuMig==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + }, + "engines": { + "node": ">=14.18" + }, + "funding": { + "url": "https://github.com/chalk/supports-hyperlinks?sponsor=1" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/svg-parser": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.4.tgz", + "integrity": "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==", + "dev": true + }, + "node_modules/svg-tags": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz", + "integrity": "sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==", + "dev": true + }, + "node_modules/svgo": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.3.3.tgz", + "integrity": "sha512-+wn7I4p7YgJhHs38k2TNjy1vCfPIfLIJWR5MnCStsN8WuuTcBnRKcMHQLMM2ijxGZmDoZwNv8ipl5aTTen62ng==", + "dev": true, + "dependencies": { + "commander": "^7.2.0", + "css-select": "^5.1.0", + "css-tree": "^2.3.1", + "css-what": "^6.1.0", + "csso": "^5.0.5", + "picocolors": "^1.0.0", + "sax": "^1.5.0" + }, + "bin": { + "svgo": "bin/svgo" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/svgo" + } + }, + "node_modules/svgo/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/svgo/node_modules/css-tree": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", + "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", + "dev": true, + "dependencies": { + "mdn-data": "2.0.30", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, + "node_modules/svgo/node_modules/mdn-data": { + "version": "2.0.30", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", + "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", + "dev": true + }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true + }, + "node_modules/synckit": { + "version": "0.11.12", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.12.tgz", + "integrity": "sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ==", + "dev": true, + "dependencies": { + "@pkgr/core": "^0.2.9" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/synckit" + } + }, + "node_modules/table": { + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/table/-/table-6.9.0.tgz", + "integrity": "sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==", + "dev": true, + "dependencies": { + "ajv": "^8.0.1", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/table/node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/table/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/tannin": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/tannin/-/tannin-1.2.0.tgz", + "integrity": "sha512-U7GgX/RcSeUETbV7gYgoz8PD7Ni4y95pgIP/Z6ayI3CfhSujwKEBlGFTCRN+Aqnuyf4AN2yHL+L8x+TCGjb9uA==", + "dependencies": { + "@tannin/plural-forms": "^1.1.0" + } + }, + "node_modules/tapable": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz", + "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/tar-fs": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.1.2.tgz", + "integrity": "sha512-QGxxTxxyleAdyM3kpFs14ymbYmNFrfY+pHj7Z8FgtbZ7w2//VAgLMac7sT6nRpIHjppXO2AwwEOg0bPFVRcmXw==", + "dev": true, + "dependencies": { + "pump": "^3.0.0", + "tar-stream": "^3.1.5" + }, + "optionalDependencies": { + "bare-fs": "^4.0.1", + "bare-path": "^3.0.0" + } + }, + "node_modules/tar-stream": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.2.0.tgz", + "integrity": "sha512-ojzvCvVaNp6aOTFmG7jaRD0meowIAuPc3cMMhSgKiVWws1GyHbGd/xvnyuRKcKlMpt3qvxx6r0hreCNITP9hIg==", + "dev": true, + "dependencies": { + "b4a": "^1.6.4", + "bare-fs": "^4.5.5", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" + } + }, + "node_modules/tar-stream/node_modules/b4a": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.8.1.tgz", + "integrity": "sha512-aiqre1Nr0B/6DgE2N5vwTc+2/oQZ4Wh1t4NznYY4E00y8LCt6NqdRv81so00oo27D8MVKTpUa/MwUUtBLXCoDw==", + "dev": true, + "peerDependencies": { + "react-native-b4a": "*" + }, + "peerDependenciesMeta": { + "react-native-b4a": { + "optional": true + } + } + }, + "node_modules/teex": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/teex/-/teex-1.0.1.tgz", + "integrity": "sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==", + "dev": true, + "dependencies": { + "streamx": "^2.12.5" + } + }, + "node_modules/terser": { + "version": "5.48.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.48.0.tgz", + "integrity": "sha512-J/9An6vs9Us6wKRriSFXBWdRZapREHqFzdNUKk0pmu804EMR6dr6winwo7e5JDxN4xahxQsuysyYFwlwj4XN/Q==", + "dev": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.15.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.6.0.tgz", + "integrity": "sha512-Eum+5ajkaOhf5KbM26osvv21kLD7BaGqQ1UA4Ami4arYwylmGUQTgHFpHDdmJod1q4QXa66p0to/FBKID+J1vA==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.25", + "jest-worker": "^27.4.5", + "schema-utils": "^4.3.0", + "terser": "^5.31.1" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@minify-html/node": { + "optional": true + }, + "@swc/core": { + "optional": true + }, + "@swc/css": { + "optional": true + }, + "@swc/html": { + "optional": true + }, + "clean-css": { + "optional": true + }, + "cssnano": { + "optional": true + }, + "csso": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "html-minifier-terser": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "postcss": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/terser-webpack-plugin/node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/terser-webpack-plugin/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "node_modules/terser/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/terser/node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/test-exclude/node_modules/brace-expansion": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/test-exclude/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/text-decoder": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.7.tgz", + "integrity": "sha512-vlLytXkeP4xvEq2otHeJfSQIRyWxo/oZGEbXrtEEF9Hnmrdly59sUbzZ/QgyWuLYHctCHxFF4tRQZNQ9k60ExQ==", + "dev": true, + "dependencies": { + "b4a": "^1.6.4" + } + }, + "node_modules/text-decoder/node_modules/b4a": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.8.1.tgz", + "integrity": "sha512-aiqre1Nr0B/6DgE2N5vwTc+2/oQZ4Wh1t4NznYY4E00y8LCt6NqdRv81so00oo27D8MVKTpUa/MwUUtBLXCoDw==", + "dev": true, + "peerDependencies": { + "react-native-b4a": "*" + }, + "peerDependenciesMeta": { + "react-native-b4a": { + "optional": true + } + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/third-party-web": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/third-party-web/-/third-party-web-0.27.0.tgz", + "integrity": "sha512-h0JYX+dO2Zr3abCQpS6/uFjujaOjA1DyDzGQ41+oFn9VW/ARiq9g5ln7qEP9+BTzDpOMyIfsfj4OvfgXAsMUSA==", + "dev": true + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true + }, + "node_modules/thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", + "dev": true + }, + "node_modules/tinyglobby": { + "version": "0.2.16", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz", + "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==", + "dev": true, + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/tldts-core": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.4.0.tgz", + "integrity": "sha512-/mb9kRld+x1sIMXxWNOAp5m6C+D4GrAORWlJkOJ5dElvxdN1eutz/o7qHLp9gFvDF4Y3/L2xeScoxz6AbEo8rQ==", + "dev": true + }, + "node_modules/tldts-icann": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/tldts-icann/-/tldts-icann-7.4.0.tgz", + "integrity": "sha512-guDQQAxukhpUJB4ax1Is9tWrSYRbvDAJFSMPCHSSc+C5viEfLpoF5KELybFUuw0nno2R2sP+oXHfAxZkbSd8KQ==", + "dev": true, + "dependencies": { + "tldts-core": "^7.4.0" + } + }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/totalist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/tough-cookie": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz", + "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==", + "dev": true, + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tr46": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", + "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", + "dev": true, + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true, + "bin": { + "tree-kill": "cli.js" + } + }, + "node_modules/trim-newlines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", + "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/trim-repeated": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz", + "integrity": "sha512-pkonvlKk8/ZuR0D5tLW8ljt5I8kmxp2XKymhepUeOdCEfKpZaktSArkLHZt76OB1ZvO9bssUsDty4SWhLvZpLg==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^1.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/trim-repeated/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/ts-api-utils": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz", + "integrity": "sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==", + "dev": true, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/tsconfig-paths": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", + "dev": true, + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tsconfig-paths/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/tsconfig-paths/node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" + }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, + "node_modules/tsutils/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "dev": true, + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", + "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", + "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.15", + "reflect.getprototypeof": "^1.0.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz", + "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0", + "reflect.getprototypeof": "^1.0.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-query-selector": { + "version": "2.12.2", + "resolved": "https://registry.npmjs.org/typed-query-selector/-/typed-query-selector-2.12.2.tgz", + "integrity": "sha512-EOPFbyIub4ngnEdqi2yOcNeDLaX/0jcE1JoAXQDDMIthap7FoN795lc/SHfIq2d416VufXpM8z/lD+WRm2gfOQ==", + "dev": true + }, + "node_modules/typescript": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", + "dev": true, + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/uc.micro": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", + "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", + "dev": true + }, + "node_modules/unbox-primitive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", + "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", + "dev": true, + "dependencies": { + "call-bound": "^1.0.3", + "has-bigints": "^1.0.2", + "has-symbols": "^1.1.0", + "which-boxed-primitive": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/unbzip2-stream": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", + "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==", + "dev": true, + "dependencies": { + "buffer": "^5.2.1", + "through": "^2.3.8" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", + "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dev": true, + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.1.tgz", + "integrity": "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.2.0.tgz", + "integrity": "sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/unrs-resolver": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.12.2.tgz", + "integrity": "sha512-dmlRxBJJayXjqTwC+JtF1HhJmgf3ftQ3YejFcZrf4+KKtJv0qDsK1pjqaaVjG7wJ5NJ6UVP1OqRMQ71Z4C3rxQ==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "napi-postinstall": "^0.3.4" + }, + "funding": { + "url": "https://opencollective.com/unrs-resolver" + }, + "optionalDependencies": { + "@unrs/resolver-binding-android-arm-eabi": "1.12.2", + "@unrs/resolver-binding-android-arm64": "1.12.2", + "@unrs/resolver-binding-darwin-arm64": "1.12.2", + "@unrs/resolver-binding-darwin-x64": "1.12.2", + "@unrs/resolver-binding-freebsd-x64": "1.12.2", + "@unrs/resolver-binding-linux-arm-gnueabihf": "1.12.2", + "@unrs/resolver-binding-linux-arm-musleabihf": "1.12.2", + "@unrs/resolver-binding-linux-arm64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-arm64-musl": "1.12.2", + "@unrs/resolver-binding-linux-loong64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-loong64-musl": "1.12.2", + "@unrs/resolver-binding-linux-ppc64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-riscv64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-riscv64-musl": "1.12.2", + "@unrs/resolver-binding-linux-s390x-gnu": "1.12.2", + "@unrs/resolver-binding-linux-x64-gnu": "1.12.2", + "@unrs/resolver-binding-linux-x64-musl": "1.12.2", + "@unrs/resolver-binding-openharmony-arm64": "1.12.2", + "@unrs/resolver-binding-wasm32-wasi": "1.12.2", + "@unrs/resolver-binding-win32-arm64-msvc": "1.12.2", + "@unrs/resolver-binding-win32-ia32-msvc": "1.12.2", + "@unrs/resolver-binding-win32-x64-msvc": "1.12.2" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/upper-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-2.0.2.tgz", + "integrity": "sha512-KgdgDGJt2TpuwBUIjgG6lzw2GWFRCW9Qkfkiv0DxqHHLYJHmtmdUIKcZd8rHgFSjopVTlw6ggzCm1b8MFQwikg==", + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/upper-case-first": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/upper-case-first/-/upper-case-first-2.0.2.tgz", + "integrity": "sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg==", + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url-loader": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-4.1.1.tgz", + "integrity": "sha512-3BTV812+AVHHOJQO8O5MkWgZ5aosP7GnROJwvzLS9hWDj00lZ6Z0wNak423Lp9PBZN05N+Jk/N5Si8jRAlGyWA==", + "dev": true, + "dependencies": { + "loader-utils": "^2.0.0", + "mime-types": "^2.1.27", + "schema-utils": "^3.0.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "file-loader": "*", + "webpack": "^4.0.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "file-loader": { + "optional": true + } + } + }, + "node_modules/url-loader/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dev": true, + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "deprecated": "uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028).", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/v8-to-istanbul": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", + "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/validate-npm-package-license/node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/validate-npm-package-name": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.1.tgz", + "integrity": "sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/w3c-xmlserializer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz", + "integrity": "sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==", + "dev": true, + "dependencies": { + "xml-name-validator": "^4.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/wait-on": { + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-8.0.5.tgz", + "integrity": "sha512-J3WlS0txVHkhLRb2FsmRg3dkMTCV1+M6Xra3Ho7HzZDHpE7DCOnoSoCJsZotrmW3uRMhvIJGSKUKrh/MeF4iag==", + "dev": true, + "dependencies": { + "axios": "^1.12.1", + "joi": "^18.0.1", + "lodash": "^4.17.21", + "minimist": "^1.2.8", + "rxjs": "^7.8.2" + }, + "bin": { + "wait-on": "bin/wait-on" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "dependencies": { + "makeerror": "1.0.12" + } + }, + "node_modules/watchpack": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.5.1.tgz", + "integrity": "sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==", + "dev": true, + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dev": true, + "dependencies": { + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/web-vitals": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-4.2.4.tgz", + "integrity": "sha512-r4DIlprAGwJ7YM11VZp4R884m0Vmgr6EAKe3P+kO0PPj3Unqyvv59rczf6UiGcb9Z8QxZVcqKNwv/g0WNdWwsw==", + "dev": true + }, + "node_modules/webdriver-bidi-protocol": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/webdriver-bidi-protocol/-/webdriver-bidi-protocol-0.4.1.tgz", + "integrity": "sha512-ARrjNjtWRRs2w4Tk7nqrf2gBI0QXWuOmMCx2hU+1jUt6d00MjMxURrhxhGbrsoiZKJrhTSTzbIrc554iKI10qw==", + "dev": true + }, + "node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/webpack": { + "version": "5.107.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.107.1.tgz", + "integrity": "sha512-mvdIWxj/H6QsfgDdH9djne3a5dYcmEmtsXGESkypaGN5jXjF/b+9KDlmTDQ2TKlFUeA2fI9Y65kihD30JOdB+Q==", + "dev": true, + "dependencies": { + "@types/estree": "^1.0.8", + "@types/json-schema": "^7.0.15", + "@webassemblyjs/ast": "^1.14.1", + "@webassemblyjs/wasm-edit": "^1.14.1", + "@webassemblyjs/wasm-parser": "^1.14.1", + "acorn": "^8.16.0", + "acorn-import-phases": "^1.0.3", + "browserslist": "^4.28.1", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.21.4", + "es-module-lexer": "^2.1.0", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.11", + "loader-runner": "^4.3.2", + "mime-db": "^1.54.0", + "neo-async": "^2.6.2", + "schema-utils": "^4.3.3", + "tapable": "^2.3.0", + "terser-webpack-plugin": "^5.5.0", + "watchpack": "^2.5.1", + "webpack-sources": "^3.4.1" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-bundle-analyzer": { + "version": "4.10.2", + "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.10.2.tgz", + "integrity": "sha512-vJptkMm9pk5si4Bv922ZbKLV8UTT4zib4FPgXMhgzUny0bfDDkLXAVQs3ly3fS4/TN9ROFtb0NFrm04UXFE/Vw==", + "dev": true, + "dependencies": { + "@discoveryjs/json-ext": "0.5.7", + "acorn": "^8.0.4", + "acorn-walk": "^8.0.0", + "commander": "^7.2.0", + "debounce": "^1.2.1", + "escape-string-regexp": "^4.0.0", + "gzip-size": "^6.0.0", + "html-escaper": "^2.0.2", + "opener": "^1.5.2", + "picocolors": "^1.0.0", + "sirv": "^2.0.3", + "ws": "^7.3.1" + }, + "bin": { + "webpack-bundle-analyzer": "lib/bin/analyzer.js" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/webpack-bundle-analyzer/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/webpack-bundle-analyzer/node_modules/ws": { + "version": "7.5.11", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.11.tgz", + "integrity": "sha512-zS54Oen9bITtp7kp2XM3AydrCIq1D+HwJOuH+c+e4LfpL/lotP5osijd+UoMnxwAam1GN8R4KtLAyIrIcBNpiA==", + "dev": true, + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/webpack-cli": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.1.4.tgz", + "integrity": "sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==", + "dev": true, + "dependencies": { + "@discoveryjs/json-ext": "^0.5.0", + "@webpack-cli/configtest": "^2.1.1", + "@webpack-cli/info": "^2.0.2", + "@webpack-cli/serve": "^2.0.5", + "colorette": "^2.0.14", + "commander": "^10.0.1", + "cross-spawn": "^7.0.3", + "envinfo": "^7.7.3", + "fastest-levenshtein": "^1.0.12", + "import-local": "^3.0.2", + "interpret": "^3.1.1", + "rechoir": "^0.8.0", + "webpack-merge": "^5.7.3" + }, + "bin": { + "webpack-cli": "bin/cli.js" + }, + "engines": { + "node": ">=14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "5.x.x" + }, + "peerDependenciesMeta": { + "@webpack-cli/generators": { + "optional": true + }, + "webpack-bundle-analyzer": { + "optional": true + }, + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/webpack-cli/node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "dev": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/webpack-dev-middleware": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz", + "integrity": "sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q==", + "dev": true, + "dependencies": { + "colorette": "^2.0.10", + "memfs": "^3.4.3", + "mime-types": "^2.1.31", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/webpack-dev-server": { + "version": "4.15.2", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.2.tgz", + "integrity": "sha512-0XavAZbNJ5sDrCbkpWL8mia0o5WPOd2YGtxrEiZkBK9FjLppIUK2TgxK6qGD2P3hUXTJNNPVibrerKcx5WkR1g==", + "dev": true, + "dependencies": { + "@types/bonjour": "^3.5.9", + "@types/connect-history-api-fallback": "^1.3.5", + "@types/express": "^4.17.13", + "@types/serve-index": "^1.9.1", + "@types/serve-static": "^1.13.10", + "@types/sockjs": "^0.3.33", + "@types/ws": "^8.5.5", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.0.11", + "chokidar": "^3.5.3", + "colorette": "^2.0.10", + "compression": "^1.7.4", + "connect-history-api-fallback": "^2.0.0", + "default-gateway": "^6.0.3", + "express": "^4.17.3", + "graceful-fs": "^4.2.6", + "html-entities": "^2.3.2", + "http-proxy-middleware": "^2.0.3", + "ipaddr.js": "^2.0.1", + "launch-editor": "^2.6.0", + "open": "^8.0.9", + "p-retry": "^4.5.0", + "rimraf": "^3.0.2", + "schema-utils": "^4.0.0", + "selfsigned": "^2.1.1", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^5.3.4", + "ws": "^8.13.0" + }, + "bin": { + "webpack-dev-server": "bin/webpack-dev-server.js" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.37.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + }, + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-dev-server/node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/webpack-dev-server/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/webpack-dev-server/node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/webpack-merge": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "dev": true, + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/webpack-merge/node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/webpack-merge/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webpack-merge/node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webpack-merge/node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/webpack-sources": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.5.0.tgz", + "integrity": "sha512-HPuy+uuoTCaaoEoI1LQ3JN9+vrPBvEesnnX1jADHy728cHSMlq4wUc4afYqahq2B1mhQVZxCXOkNTnXltr+2vQ==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "dev": true, + "dependencies": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/whatwg-encoding": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", + "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", + "deprecated": "Use @exodus/bytes instead for a more spec-conformant and faster implementation", + "dev": true, + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-mimetype": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", + "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-url": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", + "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", + "dev": true, + "dependencies": { + "tr46": "^3.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/when-exit": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/when-exit/-/when-exit-2.1.5.tgz", + "integrity": "sha512-VGkKJ564kzt6Ms1dbgPP/yuIoQCrsFAnRbptpC5wOEsDaNsbCB2bnfnaA8i/vRs5tjUSEOtIuvl9/MyVsvQZCg==", + "dev": true + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", + "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", + "dev": true, + "dependencies": { + "is-bigint": "^1.1.0", + "is-boolean-object": "^1.2.1", + "is-number-object": "^1.1.1", + "is-string": "^1.1.1", + "is-symbol": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", + "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", + "dev": true, + "dependencies": { + "call-bound": "^1.0.2", + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", + "is-async-function": "^2.0.0", + "is-date-object": "^1.1.0", + "is-finalizationregistry": "^1.1.0", + "is-generator-function": "^1.0.10", + "is-regex": "^1.2.1", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.1.0", + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-collection": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", + "dev": true, + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.20", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.20.tgz", + "integrity": "sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/wildcard": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", + "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", + "dev": true + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/write-file-atomic": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/ws": { + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", + "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xdg-basedir": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-5.1.0.tgz", + "integrity": "sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/xml-name-validator": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", + "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true, + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "node_modules/yaml": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.3.tgz", + "integrity": "sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "dev": true, + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "3.23.8", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz", + "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..9db1a95 --- /dev/null +++ b/package.json @@ -0,0 +1,22 @@ +{ + "name": "wp-performance", + "version": "2.0.0", + "description": "WP Performance Optimizer admin app", + "private": true, + "scripts": { + "build": "wp-scripts build", + "start": "wp-scripts start", + "lint:js": "wp-scripts lint-js", + "format": "wp-scripts format" + }, + "devDependencies": { + "@wordpress/scripts": "^30.0.0" + }, + "dependencies": { + "@wordpress/api-fetch": "^7.0.0", + "@wordpress/element": "^6.0.0", + "@wordpress/i18n": "^5.0.0", + "@wordpress/url": "^4.0.0", + "lucide-react": "^1.16.0" + } +} diff --git a/readme.txt b/readme.txt index ee3ff2e..53ea2f1 100644 --- a/readme.txt +++ b/readme.txt @@ -1,280 +1,180 @@ -=== WP Performance === +=== WP Performance === Contributors: alaca Donate link: https://profiles.wordpress.org/alaca -Tags: wp performance, cache, performance, speed optimization, seo -Requires at least: 4.7 -Tested up to: 5.4 -Requires PHP: 5.6 -Stable tag: trunk +Tags: cache, performance, page speed, optimization, core web vitals +Requires at least: 6.9 +Tested up to: 7.0 +Requires PHP: 8.1 +Stable tag: 2.0.0 License: GPLv2 or later License URI: http://www.gnu.org/licenses/gpl-2.0.html -== Changelog == +Make your site fast. Page caching, CSS/JS/HTML optimization, modern images, and Core Web Vitals tools in one simple plugin. -= 1.1.8.3 = -[FIX] Cloudflare add-on - respect existing headers +== Description == -= 1.1.8.2 = -[FIX] Prefetch add-on again - -= 1.1.8.1 = -[FIX] Prefetch add-on - -= 1.1.8 = -[NEW] HTML optimization -[NEW] Google Fonts display optimization -[NEW] Exclude CSS/JS files from asynchronous loading -[UPDATE] Translations -[FIX] Asynchronous JS loading - -= 1.1.7.4 = -[FIX] Combine CSS -[FIX] Combine JS - -= 1.1.7.3 = -[FIX] Update UI - Checkboxes -[FIX] Skip dynamic files - -= 1.1.7.2 = -[FIX] Combined resource path errors -[FIX] Identifiy local resources without URL scheme - -= 1.1.7.1 = -[FIX] htaccess errors - -= 1.1.7 = -[NEW] Cloudflare Add-on - purge individual cache -[NEW] Option to keep generated JS/CSS files when flushing the cache -[FIX] Lazy Load issues in MSIE - -= 1.1.6.2 = -[FIX] HTML minify - -= 1.1.6.1 = -[FIX] Lazyload issues - -= 1.1.6 = -[NEW] Lazy load videos -[NEW] Disable Emojis -[NEW] Disable Embeds -[UPDATE] Translations -[FIX] Load/Save settings - -= 1.1.5.1 = -[FIX] Fix WooCommerce Add to cart error - -= 1.1.5 = -[IMPROVE] Minify JS -[IMPROVE] Minify CSS -[IMPROVE] Minify HTML -[IMPROVE] Images LazyLoad -[IMPROVE] Async JavaScript -[IMPROVE] Prefetch Add-on -[FIX] Cache dir path - -= 1.1.4.2 = -[IMPROVE] Minify JS -[IMPROVE] Process CSS import rules - -= 1.1.4.1 = -[FIX] Minify HTML - -= 1.1.4 = -[NEW] Multisite support -[NEW] AMP support - -= 1.1.3.4 = -[FIX] Clear log file after clearing the cache -[FIX] Wrong optimization status message in WPP metabox on edit page screen -[IMPROVE] Admin UI -[IMPROVE] Cloudflare add-on -[IMPROVE] Dynamic page preload add-on -[UPDATE] languages - -= 1.1.3.3 = -[FIX] Disable resources on selected URL -[UPDATE] Chinese language file - -= 1.1.3.2 = -[FIX] Parser minify error - -= 1.1.3.1 = -[FIX] Autoloader errors - -= 1.1.3 = -[NEW] Dynamic page preload addon -[NEW] Minify HTML - -= 1.1.2 = -[UPDATE] Chinese language file - -= 1.1.1 = -[NEW] Remove cache directory after uninstall -[IMPROVE] Move log file into cache dir -[FIX] Empty template errors - -= 1.1.0 = -[NEW] Exclude user agents from cache -[NEW] Exclude search engines from cache -[NEW] Add-ons page -[IMPROVE] Admin UI -[FIX] XML files cache - -= 1.0.9 = -[IMPROVE] JavaScript async loading -[IMPROVE] Security -[IMPROVE] Parser -[FIX] LazyLoad -[FIX] Exclude urls - -= 1.0.8.1 = -[FIX] Minor bug fixes - -= 1.0.8 = -[NEW] Cloudflare integration -[IMPROVE] Admin UI for desktop devices -[IMPROVE] Admin UI for mobile devices -[FIX] Disabled resources disappearing options -[FIX] Minor bugfixes - -= 1.0.7 = -[FIX] Add items to menu error -[FIX] Parser warnings for responsive images -[IMPROVE] Admin UI on mobile devices - -= 1.0.6 = -[NEW] Group resources ( Theme, Plugins, External ) -[IMPROVE] Security -[IMPROVE] Admin UI on mobile devices -[UPDATE] Translations -[FIX] Disable external resources -[FIX] Clear cache on front-page -[FIX] Various minor bugfixes - -= 1.0.5 = -[NEW] Drafts cleanup -[NEW] WP CLI commands - run database cleanups -[IMPROVE] Admin UI -[UPDATE] Translations -[FIX] Minor bugfixes - -= 1.0.4 = -[NEW] Resource hints -[NEW] Exclude page from Image optimization on edit page screen -[NEW] Exclude URL(s) from Image optimization -[IMPROVE] Metabox UI on Edit page -[IMPROVE] Admin UI -[UPDATE] Translations -[FIX] Cron tasks cleanup -[FIX] Combine Google fonts - -= 1.0.3 = -[NEW] Cron tasks cleanup -[NEW] Exclude page from Cache, JS and CSS optimization on edit page screen -[NEW] Admin toolbar links -[IMPROVE] Admin Database UI -[IMPROVE] Admin UI on mobile devices -[UPDATE] Translations -[FIX] htaccess backup handling -[FIX] Minor bugfixes - -= 1.0.2 = -[NEW] Detect server software -[NEW] Generate NGINX rewrite rules -[NEW] Clear collected files list -[IMPROVE] Admin UI -[UPDATE] Translations -[FIX] Htaccess permissions notice - -= 1.0.1 = -[FIX] PCRE2 parser issues -[FIX] Clear cache JS error -[NEW] Chinese translation +WP Performance makes your WordPress site load faster without the headache. Turn on a few options and the plugin handles caching, asset optimization, and image delivery for you. -== Description == +Not sure where to start? Open the **Overview** tab and pick a one-click preset (Safe, Balanced, or Aggressive). You can fine-tune anything afterwards. + +Version 2.0 is a complete rebuild with a fast new dashboard and no third-party dependencies. Everything below works together out of the box. + +### Caching ### + +* **Page cache** - serves a static HTML copy of each page, before WordPress even loads +* **Block cache** - cache just the slow parts of a page, even on pages you can't fully cache (more below) +* **Cache preloading** - warm the cache from your sitemap +* **Browser caching** - tells browsers to keep files so repeat visits are instant +* **GZIP compression** - sends smaller files to the browser +* **Object cache** - optional Redis drop-in to cut database load +* **Smart by default** - skips logged-in users and WooCommerce/EDD cart pages, and ignores tracking parameters (utm, gclid, fbclid) so clean URLs share one cache +* **Mobile cache** - keep a separate copy for mobile devices when you need it + +### CSS ### + +* Minify CSS (inline and files) +* Combine CSS files +* Load CSS without blocking the page +* Remove unused CSS, per page +* Critical CSS +* Combine Google Fonts, or host them on your own server +* Control font loading (font-display) +* DNS prefetch and preconnect hints -WP Performance is a cache & performance plugin which makes optimizing your site really easy. -This plugin generates static html files from your dynamic content and it uses mod_rewrite to load the cache files which is the fastest method. - - -### Features ### - -* Page cache -* Cache preloading -* Browser cache -* GZIP Compression -* Minify CSS, JavaScript, and HTML -* Asynchronously load CSS/JavaScript -* Combine CSS/JavaScript -* Disable CSS/JavaScript -* Resource hints -* Critical CSS path generator -* Database Cleaner -* Export/import settings -* Lazy Load images ( supports native lazy load ) -* Lazy Load videos ( supports native lazy load ) +### JavaScript ### + +* Minify JavaScript (inline and files) +* Combine JavaScript files +* Defer JavaScript +* Delay JavaScript until the visitor interacts (great for third-party scripts) +* Disable scripts you don't need, site-wide or per page + +### HTML ### + +* Minify HTML +* Remove comments and unneeded markup + +### Images and media ### + +* Lazy load images and videos (uses native browser lazy loading) * Responsive images -* Regenerate thumbs -* CDN -* WP-CLI Support -* WordPress Multisite +* Add missing width and height to stop layout shift (better CLS) +* Preload your largest image and set fetchpriority for a faster LCP +* Convert images to WebP and AVIF +* Custom image sizes and one-click thumbnail regeneration +* Disable emojis and embeds + +### Database ### + +* Clean up revisions, auto-drafts, trash, spam, transients, and stale cron tasks +* Schedule cleanups daily, weekly, or monthly + +### CDN ### + +* Rewrite asset URLs to your CDN, with exclusions + +### Tools ### + +* **Overview dashboard** with environment health checks +* **One-click presets** - Safe, Balanced, Aggressive +* **Restore points** - roll back to your last five saved configurations +* **Troubleshooting log** with a live viewer +* **Export and import** your settings +* **Per-page exclusions** from the post editor +* **WP-CLI** commands +* **Multisite** support + +### Block cache ### + +Block cache stores the rendered output of a section of a page and reuses it, even on pages that are not fully cached (like logged-in or dynamic pages). Use it three ways: + +1. **Cache block** - add the "Cache" block in the editor and put any blocks inside it +2. **Shortcode** - `[wpp_cache ttl="600"]...[/wpp_cache]` +3. **PHP** - in a template: + +`if ( wpp_cache_start( 'sidebar', [ 'ttl' => 3600 ] ) ) { expensive_render(); wpp_cache_end(); }` + +You choose how long to cache and whether to keep a separate copy per page, per device, per role, or for logged-in visitors. ### Add-ons ### -* Cloudflare integration -* Varnish cache -* Dynamic page preload +* **Cloudflare** - purge cache and control Cloudflare settings +* **Varnish** - auto-purge Varnish cache +* **Prefetch** - prefetch links on hover for instant navigation -### Supported languages ### +### WP-CLI ### -* English -* Hrvatski -* 中文 (by @cmhello) +* `wp wpp flush` - clear the page cache +* `wp wpp flush-blocks` - clear the block cache +* `wp wpp enable` - enable WP Performance +* `wp wpp disable` - temporarily disable WP Performance +* `wp wpp cleanup []` - run a database cleanup (all, trash, spam, revisions, autodrafts, transients, cron) +### Languages ### -### WP-CLI Support ### +* English +* Hrvatski (Croatian) -* **wp wpp flush** - Clear the cache -* **wp wpp disable** - Temporarily disable WP Performance -* **wp wpp enable** - Enable WP Performance -* **wp wpp cleanup** - Run all database cleanups -* **wp wpp cleanup trash** - Run trash cleanup -* **wp wpp cleanup spam** - Run spam cleanup -* **wp wpp cleanup revisions** - Run revisions cleanup -* **wp wpp cleanup drafts** - Run drafts cleanup -* **wp wpp cleanup transients** - Run transients cleanup -* **wp wpp cleanup cron** - Run cron tasks cleanup +### Report bugs ### -### Report bugs ### -If you encounter any bug, please create an issue on [Github](https://github.com/alaca/WP-Performance). +Found a bug? Please open an issue on [GitHub](https://github.com/alaca/WP-Performance). == Installation == -1. Upload "wp-performance" to the "/wp-content/plugins/" directory -2. Activate the plugin through the Plugins menu in WordPress +1. Upload the "wp-performance" folder to "/wp-content/plugins/" +2. Activate the plugin from the Plugins menu in WordPress +3. Open WP Performance and apply a preset from the Overview tab, or turn on the options you want +If you already used an older version, your existing settings are migrated automatically. == Screenshots == -1. Cache page -2. CSS optimization page -3. JavaScript optimization page -4. Images -5. DB Optimizer -6. CDN -7. Settings - +1. Overview dashboard with presets and health checks +2. Page cache settings +3. Image and media optimization +4. Database cleanup +5. Settings, restore points, and the troubleshooting log == Frequently Asked Questions == += Where do I start? = +Open the Overview tab and apply a preset. Safe is risk-free, Balanced suits most sites, and Aggressive turns everything on (test your site afterwards). -= Does WP Performance work with Nginx? = -WP Performance has support for Nginx servers, but an extra step is required to make it working properly. -Depending on your WP Performance configuration, rewrite rules will be generated and listed under the “Settings” tab. You have to copy and paste generated rules manually into the Nginx config file. += What is the block cache for? = +It caches just one section of a page. That is useful on pages you can't fully cache, like a logged-in dashboard, where one part (a menu, a product grid) is still expensive to build every time. -= Does WP Performance support WordPress Multisite? = -WP Performance supports WordPress Multisite with subdomains. += Does it work with Nginx? = +Yes. WP Performance generates the Nginx rules for you and shows them under Settings. Copy them into your server config and reload Nginx. + += Does it support Multisite? = +Yes. + += Do I need Redis? = +No. Redis is optional. If it is available, you can enable the object cache for an extra speed boost; everything else works without it. = Where can I get help? = -You can get help on the wordpress.org support forum. -If you encounter any bug, please create an issue on [Github](https://github.com/alaca/WP-Performance). \ No newline at end of file +Use the [wordpress.org support forum](https://wordpress.org/support/plugin/wp-performance), or open an issue on [GitHub](https://github.com/alaca/WP-Performance). + +== Changelog == + += 2.0.0 = +A complete rebuild with a new dashboard and many new features. +[NEW] Overview dashboard with environment health checks +[NEW] One-click presets (Safe, Balanced, Aggressive) +[NEW] Block cache - cache parts of a page via the Cache block, the [wpp_cache] shortcode, or wpp_cache_start() +[NEW] Delay JavaScript until the visitor interacts +[NEW] Remove unused CSS, per page +[NEW] Host Google Fonts locally +[NEW] Convert images to WebP and AVIF +[NEW] Preload the LCP image and set fetchpriority +[NEW] Add missing image width and height to reduce layout shift +[NEW] Redis object cache drop-in +[UPDATE] Rebuilt the cache engine, asset optimizer, and CSS/JS/HTML minifiers from scratch, with no third-party dependencies +[UPDATE] New React dashboard +[UPDATE] Existing settings are migrated automatically on update +[REMOVED] AMP support + += 1.1.8.3 = +[FIX] Cloudflare add-on - respect existing headers + +For the full history of older releases, see [changelog.txt](https://plugins.svn.wordpress.org/wp-performance/trunk/changelog.txt). diff --git a/src/Addons/Cloudflare/CloudflareApi.php b/src/Addons/Cloudflare/CloudflareApi.php new file mode 100644 index 0000000..3401d19 --- /dev/null +++ b/src/Addons/Cloudflare/CloudflareApi.php @@ -0,0 +1,133 @@ +request('POST', "/zones/{$this->zone}/purge_cache", ['purge_everything' => true]); + } + + /** @param string[] $urls */ + public function purgeUrls(array $urls): array + { + $urls = array_values(array_filter(array_map('strval', $urls))); + if ($urls === []) { + return ['success' => false, 'errors' => ['No URLs provided']]; + } + return $this->request('POST', "/zones/{$this->zone}/purge_cache", ['files' => $urls]); + } + + /** + * Push the plugin's CF settings to the zone. + * + * This runs inside the settings-save request, so the whole push is held to + * one budget: a zone that stops answering costs the admin a report, not a + * request that PHP kills after the options have already been written. + * + * @param array $cfg + * @return array setting id => error message, empty when every push succeeded + */ + public function applyAll(array $cfg, bool $withDevMode = true): array + { + $values = []; + if ($withDevMode) { + $values['development_mode'] = ! empty($cfg['dev_mode']) ? 'on' : 'off'; + } + $values['cache_level'] = (string) ($cfg['cache_level'] ?? 'aggressive'); + $values['browser_cache_ttl'] = (int) ($cfg['browser_expire'] ?? 14400); + $values['rocket_loader'] = ! empty($cfg['rocket_loader']) ? 'on' : 'off'; + $values['brotli'] = ! empty($cfg['brotli']) ? 'on' : 'off'; + + $budget = (float) apply_filters('wpp.cloudflare.push_budget', self::PUSH_BUDGET); + $deadline = microtime(true) + $budget; + + $failed = []; + foreach ($values as $id => $value) { + $timeout = (int) min(self::PUSH_TIMEOUT, floor($deadline - microtime(true))); + if ($timeout < 1) { + $failed[$id] = __('Cloudflare did not answer in time, so this setting was not applied.', 'wpp'); + continue; + } + + $result = $this->setting($id, $value, $timeout); + if (empty($result['success'])) { + $messages = self::errorMessages((array) ($result['errors'] ?? [])); + $failed[$id] = $messages[0] ?? __('Unknown Cloudflare error.', 'wpp'); + } + } + + return $failed; + } + + /** + * Cloudflare reports errors as {code, message} objects; transport failures + * are added by request() as plain strings. + * + * @param array $errors + * @return list + */ + public static function errorMessages(array $errors): array + { + $out = []; + foreach ($errors as $error) { + if (is_array($error)) { + $message = trim((string) ($error['message'] ?? '')); + $code = isset($error['code']) ? ' (' . $error['code'] . ')' : ''; + $out[] = $message === '' ? '' : $message . $code; + continue; + } + $out[] = trim((string) $error); + } + + return array_values(array_filter($out)); + } + + private function setting(string $id, mixed $value, int $timeout): array + { + return $this->request('PATCH', "/zones/{$this->zone}/settings/{$id}", ['value' => $value], $timeout); + } + + private function request(string $method, string $path, ?array $body = null, int $timeout = 15): array + { + $args = [ + 'method' => $method, + 'timeout' => $timeout, + 'headers' => [ + 'X-Auth-Email' => $this->email, + 'X-Auth-Key' => $this->key, + 'Content-Type' => 'application/json', + ], + ]; + if ($body !== null) { + $args['body'] = (string) wp_json_encode($body); + } + + $response = wp_remote_request(self::BASE . $path, $args); + if (is_wp_error($response)) { + return ['success' => false, 'errors' => [$response->get_error_message()]]; + } + + $data = json_decode((string) wp_remote_retrieve_body($response), true); + return is_array($data) ? $data : ['success' => false, 'errors' => ['Invalid response']]; + } +} diff --git a/src/Addons/Cloudflare/CloudflareController.php b/src/Addons/Cloudflare/CloudflareController.php new file mode 100644 index 0000000..462d518 --- /dev/null +++ b/src/Addons/Cloudflare/CloudflareController.php @@ -0,0 +1,129 @@ + purge everything + * POST /wpp/v1/cloudflare/purge-custom -> purge the posted URLs, or the saved ones + * GET /wpp/v1/cloudflare/status -> zone settings the last save could not apply + */ +final class CloudflareController +{ + private const NS = 'wpp/v1'; + + public function __construct(private SettingsService $settings) + { + } + + public function registerRoutes(): void + { + register_rest_route(self::NS, '/cloudflare/purge', [ + [ + 'methods' => WP_REST_Server::CREATABLE, + 'callback' => [$this, 'purge'], + 'permission_callback' => [$this, 'canAccess'], + ], + ]); + register_rest_route(self::NS, '/cloudflare/purge-custom', [ + [ + 'methods' => WP_REST_Server::CREATABLE, + 'callback' => [$this, 'purgeCustom'], + 'permission_callback' => [$this, 'canAccess'], + 'args' => [ + 'urls' => [ + 'type' => 'array', + 'items' => ['type' => 'string'], + ], + ], + ], + ]); + register_rest_route(self::NS, '/cloudflare/status', [ + [ + 'methods' => WP_REST_Server::READABLE, + 'callback' => [$this, 'status'], + 'permission_callback' => [$this, 'canAccess'], + ], + ]); + } + + public function canAccess(): bool + { + return current_user_can('manage_options'); + } + + public function purge(): WP_REST_Response + { + $api = $this->api(); + if ($api === null) { + return $this->error(); + } + return $this->result($api->purgeAll()); + } + + public function purgeCustom(WP_REST_Request $request): WP_REST_Response + { + $api = $this->api(); + if ($api === null) { + return $this->error(); + } + + $posted = $request->get_param('urls'); + $urls = is_array($posted) && $posted !== [] + ? array_map('esc_url_raw', array_map('strval', $posted)) + : (array) ($this->settings->get('cloudflare')['custom_purge_urls'] ?? []); + + return $this->result($api->purgeUrls(array_values(array_filter($urls)))); + } + + public function status(): WP_REST_Response + { + return new WP_REST_Response([ + 'errors' => (array) get_option(CloudflareModule::ERRORS_OPTION, []), + ], 200); + } + + private function api(): ?CloudflareApi + { + $cf = $this->settings->get('cloudflare'); + if (empty($cf['enabled']) || empty($cf['email']) || empty($cf['api_key']) || empty($cf['zone_id'])) { + return null; + } + return new CloudflareApi((string) $cf['email'], (string) $cf['api_key'], (string) $cf['zone_id']); + } + + /** + * A non-2xx body is what api-fetch throws to the client, and it reads + * 'message', so the reason has to travel in that key. + */ + private function result(array $response): WP_REST_Response + { + $ok = ! empty($response['success']); + $errors = CloudflareApi::errorMessages((array) ($response['errors'] ?? [])); + + return new WP_REST_Response([ + 'success' => $ok, + 'code' => $ok ? 'wpp_cloudflare_ok' : 'wpp_cloudflare_error', + 'message' => $ok ? '' : ($errors[0] ?? __('Cloudflare rejected the request.', 'wpp')), + 'errors' => $errors, + ], $ok ? 200 : 400); + } + + private function error(): WP_REST_Response + { + $message = __('Cloudflare is not configured.', 'wpp'); + + return new WP_REST_Response([ + 'success' => false, + 'code' => 'wpp_cloudflare_not_configured', + 'message' => $message, + 'errors' => [$message], + ], 400); + } +} diff --git a/src/Addons/Cloudflare/CloudflareModule.php b/src/Addons/Cloudflare/CloudflareModule.php new file mode 100644 index 0000000..45e2f5c --- /dev/null +++ b/src/Addons/Cloudflare/CloudflareModule.php @@ -0,0 +1,88 @@ + 'wpp_cloudflare', + 'defaults' => [ + 'enabled' => false, + 'api_key' => '', + 'email' => '', + 'zone_id' => '', + 'dev_mode' => false, + 'cache_level' => 'aggressive', + 'browser_expire' => 14400, + 'rocket_loader' => false, + 'brotli' => false, + 'custom_purge_urls' => [], + ], + ]; + return $groups; + }); + + $settings = $container->get(SettingsService::class); + + add_action('wpp.settings.updated', static function (string $group) use ($settings): void { + if ($group !== 'cloudflare') { + return; + } + $cf = $settings->get('cloudflare'); + if (empty($cf['enabled']) || empty($cf['email']) || empty($cf['api_key']) || empty($cf['zone_id'])) { + return; + } + + // Cloudflare turns development mode off by itself after three hours, + // so re-asserting a stale 'on' would bypass the whole cache again. + $dev = ! empty($cf['dev_mode']); + $pushed = get_option(self::DEV_MODE_OPTION, null); + $withDev = $pushed === null || (bool) $pushed !== $dev; + + $api = new CloudflareApi((string) $cf['email'], (string) $cf['api_key'], (string) $cf['zone_id']); + $failed = $api->applyAll($cf, $withDev); + + if ($withDev && ! isset($failed['development_mode'])) { + update_option(self::DEV_MODE_OPTION, $dev, false); + } + + $logger = new Logger($settings); + foreach ($failed as $id => $message) { + $logger->log(sprintf('Cloudflare: %s was not applied (%s)', $id, $message)); + } + + if ($failed === []) { + delete_option(self::ERRORS_OPTION); + return; + } + update_option(self::ERRORS_OPTION, $failed, false); + }, 10, 2); + + add_action('wpp.rest.register', static function ($registry) use ($settings): void { + $registry->add(new CloudflareController($settings)); + }); + } +} diff --git a/src/Addons/Prefetch/PrefetchModule.php b/src/Addons/Prefetch/PrefetchModule.php new file mode 100644 index 0000000..be33e7b --- /dev/null +++ b/src/Addons/Prefetch/PrefetchModule.php @@ -0,0 +1,147 @@ + */ + private array $config = []; + + public function id(): string + { + return 'prefetch'; + } + + public function boot(Container $container): void + { + add_filter('wpp.settings.groups', static function (array $groups): array { + $groups['prefetch'] = [ + 'option' => 'wpp_prefetch', + 'defaults' => [ + 'enabled' => false, + 'mode' => 'prerender', // prerender | prefetch + 'eagerness' => 'moderate', // conservative | moderate | eager + 'exclude' => [], + ], + ]; + return $groups; + }); + + if (is_admin()) { + return; + } + + $config = $container->get(SettingsService::class)->get('prefetch'); + if (empty($config['enabled'])) { + return; + } + + $this->config = $config; + add_action('wp_footer', [$this, 'speculationRules'], 99); + add_action('wp_footer', [$this, 'fallback'], 100); + } + + public function speculationRules(): void + { + $mode = ($this->config['mode'] ?? '') === 'prefetch' ? 'prefetch' : 'prerender'; + + // Same-origin links only, minus admin/login, query-string action links + // (logout, add-to-cart, etc.), and anything marked nofollow. + $conditions = [ + ['href_matches' => '/*'], + ['not' => ['href_matches' => '/*\\?*']], + ['not' => ['selector_matches' => '[rel~="nofollow"]']], + ]; + foreach ($this->exclusions() as $pattern) { + $conditions[] = ['not' => ['href_matches' => $pattern]]; + } + + $rules = [ + $mode => [[ + 'source' => 'document', + 'where' => ['and' => $conditions], + 'eagerness' => $this->eagerness(), + ]], + ]; + + echo '\n"; + } + + /** + * Prefetch for browsers without Speculation Rules support. It gets the same + * exclusions and eagerness as the rules above; only prerendering is beyond + * it, so 'mode' has no fallback equivalent. + */ + public function fallback(): void + { + $eagerness = $this->eagerness(); + $config = [ + 'exclude' => array_map([$this, 'toRegex'], $this->exclusions()), + 'event' => $eagerness === 'conservative' ? 'pointerdown' : 'mouseover', + 'eager' => $eagerness === 'eager', + ]; + + echo '' . "\n"; + } + + /** @return list URL patterns no handler may ever prefetch. */ + private function exclusions(): array + { + $patterns = [ + (string) parse_url(admin_url('/'), PHP_URL_PATH) . '*', + (string) parse_url(wp_login_url(), PHP_URL_PATH) . '*', + ]; + + foreach ((array) ($this->config['exclude'] ?? []) as $pattern) { + $pattern = trim((string) $pattern); + if ($pattern !== '') { + $patterns[] = $pattern; + } + } + + return $patterns; + } + + private function eagerness(): string + { + return in_array($this->config['eagerness'] ?? '', ['conservative', 'moderate', 'eager'], true) + ? (string) $this->config['eagerness'] + : 'moderate'; + } + + /** Speculation Rules glob to a JavaScript regular expression source. */ + private function toRegex(string $pattern): string + { + $escaped = str_replace( + ['\\', '/', '.', '+', '?', '^', '$', '{', '}', '(', ')', '|', '[', ']'], + ['\\\\', '\\/', '\\.', '\\+', '\\?', '\\^', '\\$', '\\{', '\\}', '\\(', '\\)', '\\|', '\\[', '\\]'], + $pattern + ); + + return '^' . str_replace('*', '.*', $escaped) . '$'; + } +} diff --git a/src/Addons/Varnish/VarnishClient.php b/src/Addons/Varnish/VarnishClient.php new file mode 100644 index 0000000..38af21a --- /dev/null +++ b/src/Addons/Varnish/VarnishClient.php @@ -0,0 +1,37 @@ + $cfg */ + public function purge(array $cfg): void + { + $custom = trim((string) ($cfg['custom_host'] ?? '')); + $target = $custom !== '' ? $custom : home_url('/'); + + $parsed = wp_parse_url($target); + if (! is_array($parsed) || empty($parsed['host'])) { + return; + } + + $scheme = $parsed['scheme'] ?? 'http'; + $port = isset($parsed['port']) ? ':' . (int) $parsed['port'] : ''; + $purgeUrl = $scheme . '://' . $parsed['host'] . $port . '/.*'; + + wp_remote_request($purgeUrl, [ + 'method' => 'PURGE', + 'blocking' => false, + 'timeout' => 2, + 'headers' => [ + 'host' => (string) wp_parse_url(home_url(), PHP_URL_HOST), + 'X-Purge-Method' => 'regex', + ], + ]); + } +} diff --git a/src/Addons/Varnish/VarnishModule.php b/src/Addons/Varnish/VarnishModule.php new file mode 100644 index 0000000..a8c7627 --- /dev/null +++ b/src/Addons/Varnish/VarnishModule.php @@ -0,0 +1,40 @@ + 'wpp_varnish', + 'defaults' => ['enabled' => false, 'custom_host' => ''], + ]; + return $groups; + }); + + $settings = $container->get(SettingsService::class); + if (empty($settings->get('varnish')['enabled'])) { + return; + } + + add_action('wpp.cache.after_clear', static function () use ($settings): void { + (new VarnishClient())->purge($settings->get('varnish')); + }); + } +} diff --git a/src/Admin/AdminAssets.php b/src/Admin/AdminAssets.php new file mode 100644 index 0000000..78051bd --- /dev/null +++ b/src/Admin/AdminAssets.php @@ -0,0 +1,101 @@ + 'enqueue']; + } + + public function enqueue(): void + { + if (! $this->isPluginPage()) { + return; + } + + $asset = $this->asset('admin/app'); + + wp_enqueue_script( + self::HANDLE, + WPP_URL . 'build/admin/app/index.js', + $asset['dependencies'], + $asset['version'], + true + ); + + wp_set_script_translations(self::HANDLE, 'wpp', WPP_DIR . 'languages'); + + // Version the stylesheet by its own mtime: wp-scripts ties the CSS version to + // the JS content hash, so a CSS-only change would otherwise not bust the cache. + $cssFile = WPP_DIR . 'build/admin/app.css'; + $cssVer = file_exists($cssFile) ? (string) filemtime($cssFile) : $asset['version']; + + wp_enqueue_style( + self::HANDLE, + WPP_URL . 'build/admin/app.css', + [], + $cssVer + ); + + // Swaps in the built app-rtl.css on right-to-left locales. + wp_style_add_data(self::HANDLE, 'rtl', 'replace'); + + $payload = [ + 'rest' => esc_url_raw(rest_url('wpp/v1/')), + 'nonce' => wp_create_nonce('wp_rest'), + 'slug' => WPP_SLUG, + 'version' => WPP_VERSION, + 'adminUrl' => esc_url_raw(admin_url('admin.php?page=' . WPP_SLUG)), + 'siteUrl' => esc_url_raw(home_url('/')), + 'settings' => $this->settings->all(), + 'caps' => [ + 'redis' => extension_loaded('redis'), + 'memcached' => class_exists('Memcached'), + 'webp' => function_exists('imagewebp'), + 'avif' => function_exists('imageavif'), + 'opcache' => function_exists('opcache_get_status'), + ], + ]; + + wp_add_inline_script( + self::HANDLE, + 'window.WPP = Object.assign(window.WPP || {}, ' . wp_json_encode($payload) . ');', + 'before' + ); + } + + /** @return array{dependencies: string[], version: string} */ + private function asset(string $name): array + { + $file = WPP_DIR . "build/{$name}/index.asset.php"; + if (file_exists($file)) { + /** @var array{dependencies: string[], version: string} $data */ + $data = require $file; + return $data; + } + return ['dependencies' => [], 'version' => WPP_VERSION]; + } + + private function isPluginPage(): bool + { + $page = isset($_GET['page']) ? sanitize_key((string) $_GET['page']) : ''; + return $page === WPP_SLUG; + } +} diff --git a/src/Admin/AdminMenu.php b/src/Admin/AdminMenu.php new file mode 100644 index 0000000..b16519a --- /dev/null +++ b/src/Admin/AdminMenu.php @@ -0,0 +1,50 @@ + 'registerMenu']; + } + + public function registerMenu(): void + { + add_menu_page( + __('WP Performance', 'wpp'), + __('WP Performance', 'wpp'), + 'manage_options', + WPP_SLUG, + [$this, 'render'], + $this->icon(), + 80 + ); + } + + /** + * The plugin mark as a menu icon. Single colour in the default menu grey: + * WordPress only varies opacity between states, so the fill is baked in. + */ + private function icon(): string + { + $svg = '' + . '' + . ''; + + return 'data:image/svg+xml;base64,' . base64_encode($svg); + } + + public function render(): void + { + echo '
    '; + } +} diff --git a/src/Admin/CompatibilityNotice.php b/src/Admin/CompatibilityNotice.php new file mode 100644 index 0000000..6888160 --- /dev/null +++ b/src/Admin/CompatibilityNotice.php @@ -0,0 +1,68 @@ + 'WP Rocket', + 'w3-total-cache/w3-total-cache.php' => 'W3 Total Cache', + 'wp-super-cache/wp-cache.php' => 'WP Super Cache', + 'litespeed-cache/litespeed-cache.php' => 'LiteSpeed Cache', + 'wp-fastest-cache/wpFastestCache.php' => 'WP Fastest Cache', + 'cache-enabler/cache-enabler.php' => 'Cache Enabler', + 'comet-cache/comet-cache.php' => 'Comet Cache', + 'sg-cachepress/sg-cachepress.php' => 'SiteGround Optimizer', + 'breeze/breeze.php' => 'Breeze', + 'autoptimize/autoptimize.php' => 'Autoptimize', + 'hummingbird-performance/wp-hummingbird.php' => 'Hummingbird', + 'wp-optimize/wp-optimize.php' => 'WP-Optimize', + ]; + + protected function actions(): array + { + return ['admin_notices' => 'render']; + } + + public function render(): void + { + // The notice is the only warning before a drop-in is replaced, so it is + // pointless for anyone who cannot deactivate the other plugin. + if (! current_user_can('manage_options')) { + return; + } + + $active = (array) get_option('active_plugins', []); + + // Network-activated plugins live in a site option keyed by plugin file. + if (is_multisite()) { + $active = array_merge($active, array_keys((array) get_site_option('active_sitewide_plugins', []))); + } + + $found = []; + foreach (self::KNOWN as $file => $name) { + if (in_array($file, $active, true)) { + $found[] = $name; + } + } + + if ($found === []) { + return; + } + + printf( + '

    %s %s. %s

    ', + esc_html__('WP Performance detected another caching/optimization plugin:', 'wpp'), + esc_html(implode(', ', $found)), + esc_html__('Running more than one can cause conflicts; consider deactivating the others.', 'wpp') + ); + } +} diff --git a/src/Admin/Metabox.php b/src/Admin/Metabox.php new file mode 100644 index 0000000..089c873 --- /dev/null +++ b/src/Admin/Metabox.php @@ -0,0 +1,118 @@ + 'addBox', + 'save_post' => ['save', 10, 1], + ]; + } + + /** + * Named screens only. add_meta_boxes also fires on screens whose object is + * not a WP_Post (the link editor passes a bookmark), and a null screen would + * register the box there too. + */ + public function addBox(): void + { + add_meta_box( + 'wpp-exclude', + __('WP Performance', 'wpp'), + [$this, 'render'], + array_values(get_post_types(['public' => true])), + 'side', + 'default' + ); + } + + public function render(mixed $post): void + { + if (! $post instanceof WP_Post) { + return; + } + + wp_nonce_field('wpp_metabox', 'wpp_metabox_nonce'); + + $labels = [ + 'cache' => __('Exclude from cache', 'wpp'), + 'css' => __('Exclude from CSS optimization', 'wpp'), + 'js' => __('Exclude from JavaScript optimization', 'wpp'), + 'html' => __('Exclude from HTML optimization', 'wpp'), + 'image' => __('Exclude from image optimization', 'wpp'), + 'video' => __('Exclude from video lazy load', 'wpp'), + ]; + + echo '
    '; + foreach ($labels as $key => $label) { + $checked = get_post_meta($post->ID, '_wpp_exclude_' . $key, true) ? ' checked' : ''; + printf( + '

    ', + esc_attr($key), + $checked, + esc_html($label) + ); + } + echo '
    '; + } + + public function save(int $postId): void + { + $nonce = isset($_POST['wpp_metabox_nonce']) ? sanitize_text_field(wp_unslash($_POST['wpp_metabox_nonce'])) : ''; + if ($nonce === '' || ! wp_verify_nonce($nonce, 'wpp_metabox')) { + return; + } + if ((defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) || ! current_user_can('edit_post', $postId)) { + return; + } + + $selected = []; + if (isset($_POST['wpp_exclude']) && is_array($_POST['wpp_exclude'])) { + $selected = array_map('sanitize_key', array_keys(wp_unslash($_POST['wpp_exclude']))); + } + + $changed = false; + + foreach (self::TYPES as $type) { + $key = '_wpp_exclude_' . $type; + $was = (bool) get_post_meta($postId, $key, true); + $now = in_array($type, $selected, true); + + if ($was === $now) { + continue; + } + + $changed = true; + + if ($now) { + update_post_meta($postId, $key, 1); + } else { + delete_post_meta($postId, $key); + } + } + + // These exclusions are only read while a page is being written. + // advanced-cache.php runs before WordPress and has no post meta, so an + // already cached copy would keep being served until it expired. + if ($changed) { + $settings = new SettingsService(); + (new CacheStore())->clear(! empty($settings->get('cache')['keep_assets'])); + } + } +} diff --git a/src/Cache/CacheInvalidation.php b/src/Cache/CacheInvalidation.php new file mode 100644 index 0000000..eb849f6 --- /dev/null +++ b/src/Cache/CacheInvalidation.php @@ -0,0 +1,131 @@ + ['onSavePost', 10, 1], + 'deleted_post' => ['onDeletePost', 10, 1], + 'switch_theme' => 'onSwitchTheme', + 'wpp.settings.updated' => ['onSettingsUpdated', 10, 2], + 'comment_post' => ['onCommentPosted', 10, 2], + 'edit_comment' => ['onCommentChanged', 10, 1], + 'transition_comment_status' => ['onCommentTransition', 10, 2], + 'trashed_comment' => ['onCommentChanged', 10, 1], + // The drop-in picks its path scheme from a snapshot of this option, + // so a change must refresh the snapshot and drop paths built the old way. + 'update_option_permalink_structure' => 'onPermalinksChanged', + 'permalink_structure_changed' => 'onPermalinksChanged', + ]; + } + + public function onSavePost(int $postId): void + { + if (wp_is_post_revision($postId) || wp_is_post_autosave($postId)) { + return; + } + if (! empty($this->settings->get('cache')['clear_on_publish'])) { + $this->store->clear($this->keepAssets()); + } + // Block cache may wrap dynamic content (recent posts, counts) that a new + // or edited published post affects, so refresh it on content changes. + if (get_post_status($postId) === 'publish') { + $this->flushBlocks(); + } + } + + /** @param int|string $approved 1, 'approve' or 'spam', as wp_allow_comment() returns it */ + public function onCommentPosted(int $commentId, $approved = 0): void + { + // A comment held for moderation is not in anyone's rendered output yet. + if ($approved === 1 || $approved === '1' || $approved === 'approve') { + $this->onCommentChanged(); + } + } + + public function onCommentTransition(string $new, string $old): void + { + if ($new !== $old && ($new === 'approved' || $old === 'approved')) { + $this->onCommentChanged(); + } + } + + public function onCommentChanged(): void + { + if (! empty($this->settings->get('cache')['clear_on_publish'])) { + $this->store->clear($this->keepAssets()); + } + $this->flushBlocks(); + } + + public function onDeletePost(int $postId): void + { + if (! empty($this->settings->get('cache')['clear_on_delete'])) { + $this->store->clear($this->keepAssets()); + } + $this->flushBlocks(); + } + + public function onPermalinksChanged(): void + { + $this->runtime->write(); + $this->store->clear($this->keepAssets()); + $this->flushBlocks(); + } + + public function onSwitchTheme(): void + { + $this->store->clear($this->keepAssets()); + $this->flushBlocks(); + } + + /** @param array $next */ + public function onSettingsUpdated(string $group, array $next): void + { + // Keep the drop-in's runtime file current for any cache-affecting change. + $this->runtime->write(); + + // Cached HTML is the post-optimization output, so a css/js/html/media/cdn + // save is stale the moment it lands, not just a cache-group save. + if (in_array($group, self::RENDER_GROUPS, true) + && ! empty($this->settings->get('cache')['clear_on_save']) + ) { + $this->store->clear($this->keepAssets()); + } + } + + private function keepAssets(): bool + { + return ! empty($this->settings->get('cache')['keep_assets']); + } + + private function flushBlocks(): void + { + if (! empty($this->settings->get('cache')['block_cache_enabled'])) { + $this->fragments->flush(); + } + } +} diff --git a/src/Cache/CacheStore.php b/src/Cache/CacheStore.php new file mode 100644 index 0000000..d8218e7 --- /dev/null +++ b/src/Cache/CacheStore.php @@ -0,0 +1,302 @@ +writeAtomic($file, $html); + + // A stale .gz would keep being served in preference to the html, so it + // is removed whenever gzip is off or the encode fails. + $wroteGz = false; + if ($ok && $gzip && function_exists('gzencode')) { + $encoded = gzencode($html, 6); + if ($encoded !== false) { + $wroteGz = $this->writeAtomic($file . '.gz', $encoded); + } + } + if (! $wroteGz && is_file($file . '.gz')) { + @unlink($file . '.gz'); + } + + return $ok; + } + + /** + * The drop-in readfile()s these with no lock, so an in-place write would let + * a concurrent request receive a half-written (or zero-byte) page. Rename is + * atomic within a filesystem, so a reader sees either the old file or the new. + */ + private function writeAtomic(string $file, string $contents): bool + { + $tmp = $file . '.' . getmypid() . '-' . uniqid() . '.tmp'; + if (file_put_contents($tmp, $contents, LOCK_EX) === false) { + @unlink($tmp); + return false; + } + if (! @rename($tmp, $file)) { + @unlink($tmp); + return false; + } + + return true; + } + + /** + * Delete cached pages. Keeps json/log (drop-in config + log) and, optionally, css/js. + * + * On a network every blog writes into one cache directory, so a purge + * started on one site is limited to that site's pages: the generated assets + * at the root are shared, and the other blogs' pages are not this blog's to + * throw away. $network is the network-wide flush a super admin asks for. + */ + public function clear(bool $keepAssets = false, bool $network = false): void + { + if (! is_dir(WPP_CACHE_DIR)) { + return; + } + do_action('wpp.cache.before_clear'); + + $keep = ['json', 'log', 'php']; + if ($keepAssets) { + // Locally hosted fonts are referenced by the kept CSS, so dropping + // them would leave every @font-face pointing at a 404. + array_push($keep, 'css', 'js', 'woff2', 'woff', 'ttf', 'eot', 'otf'); + } + // Block-cache fragments belong to the after_clear listener, which honours + // block_cache_flush_on_clear; deleting them here ignores that setting. + $this->deleteContents(self::scope($network), $keep, self::fragmentsDir()); + + do_action('wpp.cache.after_clear'); + } + + /** Cache subtree a purge may delete from. */ + private static function scope(bool $network): string + { + if ($network || ! is_multisite()) { + return WPP_CACHE_DIR; + } + + $home = (string) home_url(); + $path = '/' . trim((string) parse_url($home, PHP_URL_PATH), '/'); + if ($path !== '/') { + $path .= '/'; + } + + // Without permalinks every page is a flat md5 file in the host + // directory, so the site path is not part of the layout to scope by. + if (! get_option('permalink_structure', '')) { + $path = '/'; + } + + return WPP_CACHE_DIR . self::sanitizeHost((string) parse_url($home, PHP_URL_HOST)) . $path; + } + + public function clearAll(): void + { + if (! is_dir(WPP_CACHE_DIR)) { + return; + } + $this->deleteContents(WPP_CACHE_DIR, []); + } + + private static function fragmentsDir(): string + { + return rtrim(WPP_CACHE_DIR, '/\\') . '/fragments'; + } + + /** Whether a path sits inside the block cache's fragment subtree. */ + private static function isFragment(string $path): bool + { + $dir = self::fragmentsDir(); + + return str_starts_with($path, $dir . '/') || str_starts_with($path, $dir . DIRECTORY_SEPARATOR); + } + + /** + * @param string[] $keepExt extensions to preserve + */ + private function deleteContents(string $dir, array $keepExt, string $skipDir = ''): void + { + if (! is_dir($dir)) { + return; + } + + // glob() would treat a cached path containing [ ] * ? as a pattern and + // return nothing, silently leaving that directory unpurged forever. + foreach (iterator_to_array(new FilesystemIterator($dir, FilesystemIterator::SKIP_DOTS)) as $item) { + $path = $item->getPathname(); + if ($item->isDir()) { + if ($skipDir !== '' && rtrim($path, '/\\') === $skipDir) { + continue; + } + $this->deleteContents($path, $keepExt, $skipDir); + @rmdir($path); + continue; + } + $name = $item->getFilename(); + if ($name === 'index.php' || $name === '.htaccess') { + continue; + } + $ext = strtolower(pathinfo($name, PATHINFO_EXTENSION)); + if (in_array($ext, $keepExt, true)) { + continue; + } + @unlink($path); + } + } + + /** Number of cached HTML pages on disk (gzip siblings, assets and block fragments excluded). */ + public function pages(): int + { + if (! is_dir(WPP_CACHE_DIR)) { + return 0; + } + + $iterator = new RecursiveIteratorIterator( + new RecursiveDirectoryIterator(WPP_CACHE_DIR, FilesystemIterator::SKIP_DOTS) + ); + + $count = 0; + foreach ($iterator as $file) { + if (self::isFragment($file->getPathname())) { + continue; + } + if ($file->isFile() && strtolower(pathinfo($file->getFilename(), PATHINFO_EXTENSION)) === 'html') { + $count++; + } + } + + return $count; + } + + /** @return array{html:int, css:int, js:int, total:int} byte sizes, block fragments excluded */ + public function stats(): array + { + $out = ['html' => 0, 'css' => 0, 'js' => 0, 'total' => 0]; + if (! is_dir(WPP_CACHE_DIR)) { + return $out; + } + + $iterator = new RecursiveIteratorIterator( + new RecursiveDirectoryIterator(WPP_CACHE_DIR, FilesystemIterator::SKIP_DOTS) + ); + + foreach ($iterator as $file) { + if (! $file->isFile() || self::isFragment($file->getPathname())) { + continue; + } + $name = $file->getFilename(); + $ext = strtolower(pathinfo($name, PATHINFO_EXTENSION)); + if (in_array($ext, ['json', 'log', 'php'], true)) { + continue; + } + if ($ext === 'gz') { + $ext = strtolower(pathinfo(substr($name, 0, -3), PATHINFO_EXTENSION)); + } + + $size = (int) $file->getSize(); + $out['total'] += $size; + if (isset($out[$ext])) { + $out[$ext] += $size; + } + } + + return $out; + } +} diff --git a/src/Cache/DropinInstaller.php b/src/Cache/DropinInstaller.php new file mode 100644 index 0000000..a9368fd --- /dev/null +++ b/src/Cache/DropinInstaller.php @@ -0,0 +1,177 @@ +copyDropin(); + if ($copied) { + $this->setWpCache(true); + } + return $copied; + } + + /** + * wp-content/advanced-cache.php and wp-config.php are network-wide root + * files. A multisite subsite administrator has manage_options but is + * deliberately not allowed to modify files, and DISALLOW_FILE_MODS is how a + * host locks writes down entirely. + */ + public static function fileModsAllowed(): bool + { + if (defined('DISALLOW_FILE_MODS') && DISALLOW_FILE_MODS) { + return false; + } + + // No current user means WP-CLI or cron, where there is nobody to check. + return ! is_multisite() || get_current_user_id() === 0 || is_super_admin(); + } + + public function uninstall(): void + { + // Only ever remove our own drop-in, and only disable WP_CACHE when we + // were the ones serving it. Another cache plugin may own this file. + if ($this->ours()) { + @unlink($this->dest()); + $this->setWpCache(false); + } + } + + /** Installed, ours, and matching the running plugin version. */ + public function dropinInstalled(): bool + { + return $this->ours() && $this->installedVersion() === $this->version(); + } + + /** A drop-in from another plugin is present and must not be touched. */ + public function foreignDropin(): bool + { + return is_file($this->dest()) && ! $this->ours(); + } + + private function dest(): string + { + return WP_CONTENT_DIR . '/advanced-cache.php'; + } + + private function version(): string + { + return defined('WPP_VERSION') ? (string) WPP_VERSION : '0'; + } + + private function ours(): bool + { + $dest = $this->dest(); + if (! is_file($dest)) { + return false; + } + + $contents = (string) @file_get_contents($dest); + if (str_contains($contents, self::STAMP)) { + return true; + } + + foreach (self::LEGACY as $marker) { + if (str_contains($contents, $marker)) { + return true; + } + } + + return false; + } + + private function installedVersion(): ?string + { + $contents = is_file($this->dest()) ? (string) @file_get_contents($this->dest()) : ''; + return preg_match("/'" . self::STAMP . "',\s*'([^']*)'/", $contents, $m) ? $m[1] : null; + } + + private function copyDropin(): bool + { + $src = WPP_DIR . 'advanced-cache.php'; + if (! file_exists($src) || $this->foreignDropin()) { + return false; + } + + $contents = file_get_contents($src); + if ($contents === false) { + return false; + } + + // Stamp the version so a plugin update refreshes a stale copy. + $contents = str_replace(self::PLACEHOLDER, $this->version(), $contents); + + return file_put_contents($this->dest(), $contents, LOCK_EX) !== false; + } + + private function setWpCache(bool $on): void + { + $config = $this->wpConfigPath(); + if ($config === null || ! is_writable($config)) { + return; + } + + $contents = file_get_contents($config); + if ($contents === false) { + return; + } + + // Turning off only removes the line we added. A WP_CACHE define placed + // there by the host or another plugin is left alone. + $pattern = $on + ? '/^[ \t]*define\(\s*[\'"]WP_CACHE[\'"]\s*,.*?\);.*$\n?/m' + : '/^[ \t]*define\(\s*[\'"]WP_CACHE[\'"]\s*,.*?\);[ \t]*' . preg_quote(self::MARKER, '/') . '.*$\n?/m'; + + $contents = preg_replace($pattern, '', $contents); + + if ($on && $contents !== null) { + $line = "define( 'WP_CACHE', true ); " . self::MARKER . "\n"; + $contents = preg_replace('/^<\?php\s*\n/', " open buffer frames (supports nesting) */ + private array $stack = []; + + /** @var array> asset snapshots taken on a block miss */ + private array $pending = []; + + public function __construct( + private SettingsService $settings, + private FragmentStore $store + ) { + } + + public function register(): void + { + add_shortcode('wpp_cache', [$this, 'shortcode']); + add_filter('pre_render_block', [$this, 'preRenderBlock'], 10, 2); + add_filter('render_block', [$this, 'renderBlock'], 10, 2); + } + + /** + * Returning a string here stops WordPress from rendering the block and its + * inner blocks at all. + * + * @param string|null $pre + * @param array $block + * @return string|null + */ + public function preRenderBlock($pre, $block) + { + if (($block['blockName'] ?? '') !== 'wpp/cache' || $this->skip()) { + return $pre; + } + + $identity = $this->blockIdentity($block); + $cached = $this->store->get($identity); + if ($cached === null) { + $this->pending[$identity] = $this->assetQueue(); + return $pre; + } + + // Short-circuiting here skips WP_Block::render(), which is where inner + // blocks enqueue their view scripts and styles, so replay them by hand. + [$html, $assets] = $this->decode($cached); + $this->enqueueAssets($assets); + + return $html; + } + + /** + * Only runs on a miss: render_block does not fire when preRenderBlock returned content. + * + * @param string $content + * @param array $block + */ + public function renderBlock($content, $block): string + { + if (($block['blockName'] ?? '') !== 'wpp/cache' || $this->skip()) { + return $content; + } + + $identity = $this->blockIdentity($block); + $before = $this->pending[$identity] ?? null; + unset($this->pending[$identity]); + + $assets = $before === null ? [] : $this->assetsAdded($before); + + $this->store->set( + $identity, + $this->encode($content, $assets), + $this->resolveTtl($this->blockOpts($block)) + ); + + return $content; + } + + public function enabled(): bool + { + return ! empty($this->settings->get('cache')['block_cache_enabled']); + } + + /** + * False on a hit (cached HTML is echoed, skip rendering); true otherwise (render, then call end()). + * + * @param array $opts + */ + public function start(string $key, array $opts = []): bool + { + if ($this->skip()) { + return true; + } + + $identity = $this->identity($key, $opts); + $cached = $this->store->get($identity); + if ($cached !== null) { + echo $cached; + return false; + } + + ob_start(); + $this->stack[] = [ + 'identity' => $identity, + 'ttl' => $this->resolveTtl($opts), + 'level' => ob_get_level(), + ]; + return true; + } + + public function end(): void + { + if ($this->stack === []) { + return; + } + $frame = array_pop($this->stack); + + // Code inside the region can close our buffer (ob_end_flush is common in + // older plugins). Grabbing whatever is innermost would then steal the + // page buffer and flush a truncated page into the page cache. + if (ob_get_level() !== $frame['level']) { + return; + } + + $html = (string) ob_get_clean(); + $this->store->set($frame['identity'], $html, $frame['ttl']); + echo $html; + } + + /** @param array $opts */ + public function wrap(string $key, array $opts, callable $callback): string + { + if ($this->skip()) { + ob_start(); + $callback(); + return (string) ob_get_clean(); + } + + $identity = $this->identity($key, $opts); + $cached = $this->store->get($identity); + if ($cached !== null) { + return $cached; + } + + ob_start(); + $callback(); + $html = (string) ob_get_clean(); + $this->store->set($identity, $html, $this->resolveTtl($opts)); + + return $html; + } + + public function shortcode(mixed $atts, ?string $content = null): string + { + $atts = shortcode_atts([ + 'key' => '', + 'ttl' => 0, + 'vary_url' => '1', + 'vary_role' => '0', + 'vary_device' => '0', + ], is_array($atts) ? $atts : [], 'wpp_cache'); + + $content = (string) $content; + $opts = [ + 'ttl' => (int) $atts['ttl'], + 'vary_url' => $this->boolAtt($atts['vary_url']), + 'vary_role' => $this->boolAtt($atts['vary_role']), + 'vary_device' => $this->boolAtt($atts['vary_device']), + ]; + $key = $atts['key'] !== '' ? (string) $atts['key'] : 'sc_' . md5($content); + + if ($this->skip()) { + return do_shortcode($content); + } + + $identity = $this->identity($key, $opts); + $cached = $this->store->get($identity); + if ($cached !== null) { + return $cached; + } + + $rendered = do_shortcode($content); + $this->store->set($identity, $rendered, $this->resolveTtl($opts)); + + return $rendered; + } + + /** @param array $opts */ + public function identity(string $key, array $opts): string + { + $parts = ['k=' . $key]; + + if ($opts['vary_url'] ?? true) { + $parts[] = 'u=' . $this->requestPath(); + } + + // Not opt-in: a logged-in render carries nonces and account-specific + // markup, and a shared entry leaks it in whichever direction fills first. + // A role bucket is not enough - two subscribers are two people. + $loggedIn = is_user_logged_in(); + $parts[] = 'l=' . ($loggedIn ? '1' : '0'); + if ($loggedIn) { + $parts[] = 'uid=' . get_current_user_id(); + } + + if ($loggedIn || ! empty($opts['vary_role'])) { + $parts[] = 'r=' . $this->currentRole(); + } + if (! empty($opts['vary_device'])) { + $parts[] = 'd=' . (wp_is_mobile() ? 'm' : 'd'); + } + + return implode('|', $parts); + } + + /** Tracking params are dropped so ?utm_* variants cannot mint endless entries. */ + private function requestPath(): string + { + $uri = (string) ($_SERVER['REQUEST_URI'] ?? '/'); + $path = (string) (parse_url($uri, PHP_URL_PATH) ?: '/'); + $query = CacheStore::strippedQuery((string) parse_url($uri, PHP_URL_QUERY)); + + return $query !== '' ? $path . '?' . $query : $path; + } + + /** @param array $block */ + private function blockIdentity(array $block): string + { + $key = 'block:' . md5(serialize_block($block)); + + // The serialized source is identical for every iteration of a Query + // Loop, so without the loop's post the first item is replayed for all. + $postId = $this->contextPostId($block); + if ($postId > 0) { + $key .= ':p' . $postId; + } + + return $this->identity($key, $this->blockOpts($block)); + } + + /** @param array $block */ + private function contextPostId(array $block): int + { + $context = $block['context']['postId'] ?? null; + if ($context !== null) { + return (int) $context; + } + + return function_exists('get_the_ID') ? (int) get_the_ID() : 0; + } + + /** + * @param array $block + * @return array + */ + private function blockOpts(array $block): array + { + $attrs = $block['attrs'] ?? []; + return [ + 'ttl' => (int) ($attrs['ttl'] ?? 0), + 'vary_url' => $attrs['varyUrl'] ?? true, + 'vary_role' => ! empty($attrs['varyRole']), + 'vary_device' => ! empty($attrs['varyDevice']), + ]; + } + + private function skip(): bool + { + if (! $this->enabled()) { + return true; + } + if (is_admin() || wp_doing_ajax() || (defined('DOING_CRON') && DOING_CRON)) { + return true; + } + return ! empty($_POST); + } + + /** @param array $opts */ + private function resolveTtl(array $opts): int + { + $ttl = (int) ($opts['ttl'] ?? 0); + if ($ttl > 0) { + return $ttl; + } + $default = (int) ($this->settings->get('cache')['block_cache_ttl'] ?? 0); + return $default > 0 ? $default : 3600; + } + + private function currentRole(): string + { + if (! is_user_logged_in()) { + return 'anon'; + } + $user = wp_get_current_user(); + return $user->roles[0] ?? 'none'; + } + + private function boolAtt(mixed $value): bool + { + return filter_var($value, FILTER_VALIDATE_BOOLEAN); + } + + /** @return array */ + private function assetQueue(): array + { + return [ + 'scripts' => isset($GLOBALS['wp_scripts']->queue) ? array_values((array) $GLOBALS['wp_scripts']->queue) : [], + 'styles' => isset($GLOBALS['wp_styles']->queue) ? array_values((array) $GLOBALS['wp_styles']->queue) : [], + 'inline' => $this->inlineStyles(), + 'rules' => $this->supportRules(), + ]; + } + + /** + * Inline CSS attached to registered handles, which the queue diff cannot see. + * + * @return array> + */ + private function inlineStyles(): array + { + $styles = $GLOBALS['wp_styles'] ?? null; + if (! is_object($styles) || ! isset($styles->registered) || ! is_array($styles->registered)) { + return []; + } + + $out = []; + foreach ($styles->registered as $handle => $item) { + $after = is_object($item) ? ($item->extra['after'] ?? null) : null; + if (is_array($after) && $after !== []) { + $out[(string) $handle] = array_values(array_filter($after, 'is_string')); + } + } + + return $out; + } + + /** + * Layout, elements, duotone and block-style-variation CSS lands in the style + * engine's block-supports store during render_block, not in a handle queue. + * + * @return array}> + */ + private function supportRules(): array + { + if (! class_exists('WP_Style_Engine_CSS_Rules_Store')) { + return []; + } + + $store = \WP_Style_Engine_CSS_Rules_Store::get_store('block-supports'); + if (! is_object($store)) { + return []; + } + + $out = []; + foreach ($store->get_all_rules() as $key => $rule) { + $declarations = $rule->get_declarations(); + if (is_object($declarations)) { + $declarations = $declarations->get_declarations(); + } + $out[(string) $key] = [ + 'selector' => (string) $rule->get_selector(), + 'rules_group' => method_exists($rule, 'get_rules_group') ? (string) $rule->get_rules_group() : '', + 'declarations' => array_map('strval', (array) $declarations), + ]; + } + + return $out; + } + + /** + * @param array $before + * @return array + */ + private function assetsAdded(array $before): array + { + $now = $this->assetQueue(); + + return [ + 'scripts' => array_values(array_diff($now['scripts'], $before['scripts'])), + 'styles' => array_values(array_diff($now['styles'], $before['styles'])), + 'inline' => $this->inlineAdded($before['inline'] ?? [], $now['inline']), + 'rules' => $this->rulesAdded($before['rules'] ?? [], $now['rules']), + ]; + } + + /** + * @param array> $before + * @param array> $now + * @return array> + */ + private function inlineAdded(array $before, array $now): array + { + $out = []; + foreach ($now as $handle => $items) { + $added = array_values(array_diff($items, $before[$handle] ?? [])); + if ($added !== []) { + $out[$handle] = $added; + } + } + + return $out; + } + + /** + * Rules are merged into whatever object already holds the selector, so the + * diff has to run per declaration rather than per selector. + * + * @param array> $before + * @param array> $now + * @return array> + */ + private function rulesAdded(array $before, array $now): array + { + $out = []; + foreach ($now as $key => $rule) { + $was = (array) ($before[$key]['declarations'] ?? []); + $added = []; + foreach ((array) $rule['declarations'] as $property => $value) { + if (($was[$property] ?? null) !== $value) { + $added[$property] = $value; + } + } + if ($added !== []) { + $out[$key] = [ + 'selector' => $rule['selector'], + 'rules_group' => $rule['rules_group'], + 'declarations' => $added, + ]; + } + } + + return $out; + } + + /** @param array $assets */ + private function enqueueAssets(array $assets): void + { + foreach ((array) ($assets['scripts'] ?? []) as $handle) { + wp_enqueue_script((string) $handle); + } + foreach ((array) ($assets['styles'] ?? []) as $handle) { + wp_enqueue_style((string) $handle); + } + foreach ((array) ($assets['inline'] ?? []) as $handle => $items) { + foreach ((array) $items as $css) { + wp_add_inline_style((string) $handle, (string) $css); + } + } + + $rules = (array) ($assets['rules'] ?? []); + if ($rules !== [] && function_exists('wp_style_engine_get_stylesheet_from_css_rules')) { + wp_style_engine_get_stylesheet_from_css_rules(array_values($rules), ['context' => 'block-supports']); + } + } + + /** @param array $assets */ + private function encode(string $html, array $assets): string + { + if (array_filter($assets) === []) { + return $html; + } + + return self::ASSETS_MARK . (string) wp_json_encode($assets) . "\x00" . $html; + } + + /** @return array{0:string, 1:array} */ + private function decode(string $raw): array + { + if (! str_starts_with($raw, self::ASSETS_MARK)) { + return [$raw, []]; + } + + $start = strlen(self::ASSETS_MARK); + $end = strpos($raw, "\x00", $start); + if ($end === false) { + return [$raw, []]; + } + + $assets = json_decode(substr($raw, $start, $end - $start), true); + + return [substr($raw, $end + 1), is_array($assets) ? $assets : []]; + } +} diff --git a/src/Cache/FragmentStore.php b/src/Cache/FragmentStore.php new file mode 100644 index 0000000..88d1959 --- /dev/null +++ b/src/Cache/FragmentStore.php @@ -0,0 +1,253 @@ +key($identity); + + if ($this->usesObjectCache()) { + $value = wp_cache_get($key, self::GROUP); + return is_string($value) ? $value : null; + } + + return $this->diskGet($key); + } + + public function set(string $identity, string $html, int $ttl): void + { + $key = $this->key($identity); + $ttl = max(0, $ttl); + + if ($this->usesObjectCache()) { + wp_cache_set($key, $html, self::GROUP, $ttl); + return; + } + + $this->diskSet($key, $html, $ttl); + } + + public function flush(): void + { + update_option(self::GEN_OPTION, $this->generation() + 1, true); + + $scope = $this->siteScope(); + if ($scope === '') { + $this->deleteDir($this->dir()); + return; + } + + // Sibling blogs keep their own generation counter, so wiping the shared + // tree would leave them serving entries they can no longer invalidate. + foreach (glob($this->dir() . '*/' . $scope . '-*.html.php') ?: [] as $file) { + @unlink($file); + } + } + + /** @return array{count:int, bytes:int} disk fragments only */ + public function stats(): array + { + $out = ['count' => 0, 'bytes' => 0]; + $dir = $this->dir(); + if (! is_dir($dir)) { + return $out; + } + + $scope = $this->siteScope(); + $iterator = new \RecursiveIteratorIterator( + new \RecursiveDirectoryIterator($dir, \FilesystemIterator::SKIP_DOTS) + ); + foreach ($iterator as $file) { + $name = $file->getFilename(); + if (! $file->isFile() || ! str_ends_with($name, '.html.php')) { + continue; + } + if ($scope !== '' && ! str_starts_with($name, $scope . '-')) { + continue; + } + $out['count']++; + $out['bytes'] += (int) $file->getSize(); + } + + return $out; + } + + private function generation(): int + { + return (int) get_option(self::GEN_OPTION, 0); + } + + /** + * Namespace for the current blog, empty off a network. + * + * Every blog shares one fragments/ tree and one identity format, so without + * this two sites running the same theme resolve to the same file. + */ + private function siteScope(): string + { + if (! function_exists('is_multisite') || ! is_multisite()) { + return ''; + } + + return 's' . get_current_blog_id(); + } + + private function key(string $identity): string + { + $scope = $this->siteScope(); + + return md5($this->generation() . '|' . ($scope !== '' ? $scope . '|' : '') . $identity); + } + + /** Deny direct HTTP access to stored fragments. */ + private function protect(): void + { + $dir = $this->dir(); + + $index = $dir . 'index.php'; + if (! is_file($index)) { + @file_put_contents($index, "\nRequire all denied\n\n\nOrder allow,deny\nDeny from all\n\n", LOCK_EX); + } + } + + private function dir(): string + { + return WPP_CACHE_DIR . self::SUBDIR; + } + + /** The blog prefix keeps flush() and stats() able to tell one blog's files from another's. */ + private function fileFor(string $key): string + { + $scope = $this->siteScope(); + + return $this->dir() . substr($key, 0, 2) . '/' . ($scope !== '' ? $scope . '-' : '') . $key . '.html.php'; + } + + private function diskGet(string $key): ?string + { + $file = $this->fileFor($key); + if (! is_file($file)) { + return null; + } + + $raw = file_get_contents($file); + if ($raw === false) { + return null; + } + + $raw = RuntimeSettings::payload($raw); + $raw = ltrim($raw, "\n"); + + $nl = strpos($raw, "\n"); + if ($nl === false) { + return null; + } + + $expiry = (int) substr($raw, 0, $nl); + if ($expiry !== 0 && $expiry < time()) { + @unlink($file); + return null; + } + + return substr($raw, $nl + 1); + } + + private function diskSet(string $key, string $html, int $ttl): void + { + $file = $this->fileFor($key); + $dir = dirname($file); + if (! is_dir($dir) && ! wp_mkdir_p($dir)) { + return; + } + + // Fragments are rendered page sections and may hold content the visitor + // was not meant to see, so the directory must not be browsable. + $this->protect(); + + // Identities carry the request URL, so an anonymous visitor can mint + // unlimited distinct entries. Refuse rather than exhaust inodes. + if (! is_file($file) && $this->shardFull($dir)) { + return; + } + + $expiry = $ttl > 0 ? time() + $ttl : 0; + $body = RuntimeSettings::GUARD . $expiry . "\n" . $html; + + // Readers take no lock, so the entry has to appear whole or not at all. + $tmp = $file . '.' . getmypid() . uniqid('', false) . '.tmp'; + if (file_put_contents($tmp, $body) === false || ! @rename($tmp, $file)) { + @unlink($tmp); + } + } + + /** Sweeps expired entries before reporting a shard as full. */ + private function shardFull(string $dir): bool + { + $files = glob(rtrim($dir, '/') . '/*.html.php'); + if (! is_array($files) || count($files) < self::MAX_PER_SHARD) { + return false; + } + + $now = time(); + $live = 0; + foreach ($files as $file) { + $handle = @fopen($file, 'r'); + if ($handle === false) { + $live++; + continue; + } + // First line is the exit guard, so the expiry is on the second. + $first = (string) fgets($handle); + $expiry = str_starts_with($first, '= self::MAX_PER_SHARD; + } + + private function deleteDir(string $dir): void + { + $items = glob(rtrim($dir, '/') . '/*'); + if ($items === false) { + return; + } + foreach ($items as $item) { + if (is_dir($item)) { + $this->deleteDir($item); + @rmdir($item); + } else { + @unlink($item); + } + } + } +} diff --git a/src/Cache/ObjectCacheInstaller.php b/src/Cache/ObjectCacheInstaller.php new file mode 100644 index 0000000..327b283 --- /dev/null +++ b/src/Cache/ObjectCacheInstaller.php @@ -0,0 +1,89 @@ +foreignDropin() || ! DropinInstaller::fileModsAllowed()) { + return false; + } + + $src = WPP_DIR . 'object-cache.php'; + if (! file_exists($src)) { + return false; + } + + $contents = @file_get_contents($src); + if ($contents === false) { + return false; + } + + return @file_put_contents($this->dest(), $this->stamp($contents), LOCK_EX) !== false; + } + + public function uninstall(): void + { + if ($this->installed()) { + @unlink($this->dest()); + } + } + + public function installed(): bool + { + return is_file($this->dest()) && str_contains((string) @file_get_contents($this->dest()), self::MARKER); + } + + /** Installed, ours, and matching the running plugin version. */ + public function objectCacheInstalled(): bool + { + return $this->installed() && $this->installedVersion() === $this->version(); + } + + /** True when an object-cache.php from another source is present. */ + public function foreignDropin(): bool + { + return is_file($this->dest()) && ! str_contains((string) @file_get_contents($this->dest()), self::MARKER); + } + + private function dest(): string + { + return WP_CONTENT_DIR . '/object-cache.php'; + } + + private function version(): string + { + return defined('WPP_VERSION') ? (string) WPP_VERSION : '0'; + } + + private function installedVersion(): ?string + { + $contents = is_file($this->dest()) ? (string) @file_get_contents($this->dest()) : ''; + return preg_match("/'" . self::STAMP . "',\s*'([^']*)'/", $contents, $m) ? $m[1] : null; + } + + /** The stamp is what tells a copy left by an earlier release from a current one. */ + private function stamp(string $contents): string + { + $define = "version() . "');\n"; + + return preg_replace('/^<\?php\s*\n/', $define, $contents, 1) ?? $contents; + } +} diff --git a/src/Cache/RuntimeSettings.php b/src/Cache/RuntimeSettings.php new file mode 100644 index 0000000..5ea6505 --- /dev/null +++ b/src/Cache/RuntimeSettings.php @@ -0,0 +1,150 @@ +file(); + if (! is_file($file)) { + return false; + } + + $data = json_decode(self::payload((string) file_get_contents($file)), true); + + return is_array($data) && ($data['version'] ?? null) === $this->version(); + } + + /** Contents with the guard prefix removed. */ + public static function payload(string $contents): string + { + return str_starts_with($contents, '\n"; + + public function file(): string + { + $home = (string) home_url(); + $host = CacheStore::sanitizeHost((string) parse_url($home, PHP_URL_HOST)); + + return WPP_CACHE_DIR . $host . self::pathKey((string) parse_url($home, PHP_URL_PATH)) . '.json.php'; + } + + /** + * Sites in a subdirectory network share a host and each has its own settings, + * so the path goes into the filename: without it every site in the network + * overwrites the same config and the last one to save owns them all. + * + * Mirrored by wpp_dropin_path_key() in advanced-cache.php. + */ + public static function pathKey(string $path): string + { + $key = ''; + foreach (array_slice(array_values(array_filter(explode('/', $path), 'strlen')), 0, 3) as $segment) { + $key .= '~' . preg_replace('/[^a-z0-9\-_]/', '-', strtolower($segment)); + } + + return $key; + } + + public function write(): void + { + if (! is_dir(WPP_CACHE_DIR)) { + wp_mkdir_p(WPP_CACHE_DIR); + } + $this->guard(); + + $cache = $this->settings->get('cache'); + + // An emptied "Clear cache after" field stores '', and an expiry of 0 + // means "never stale", which would freeze every cached page for good. + $expire = (int) ($cache['clear_time'] ?? 0) * (int) ($cache['clear_unit'] ?? 0); + if ($expire <= 0) { + $expire = self::FALLBACK_EXPIRE; + } + + $permalinks = (string) get_option('permalink_structure', ''); + + $data = [ + 'version' => $this->version(), + 'enabled' => (bool) ($cache['enabled'] ?? false), + 'disabled' => (bool) get_option('wpp_disabled', false), + 'mobile' => (bool) ($cache['mobile'] ?? false), + 'expire' => $expire, + 'permalinks' => (bool) $permalinks, + 'trailing_slash' => str_ends_with($permalinks, '/'), + 'exclude' => array_values((array) ($cache['exclude_urls'] ?? [])), + 'user_agents' => array_values((array) ($cache['exclude_user_agents'] ?? [])), + 'cache_query_strings' => (bool) ($cache['cache_query_strings'] ?? false), + 'search_bots' => (bool) ($cache['exclude_search_bots'] ?? false), + ]; + + file_put_contents($this->file(), self::GUARD . (string) wp_json_encode($data), LOCK_EX); + } + + /** + * This config lists the URLs the admin deliberately keeps out of the cache, + * and the log next to it records every cached request, so neither may be + * readable over HTTP. + */ + private function guard(): void + { + $index = WPP_CACHE_DIR . 'index.php'; + if (! is_file($index)) { + file_put_contents($index, "', + '', + 'Require all denied', + '', + '', + 'Order allow,deny', + 'Deny from all', + '', + '', + '', + ])); + } +} diff --git a/src/Cli/CliCommands.php b/src/Cli/CliCommands.php new file mode 100644 index 0000000..e95e907 --- /dev/null +++ b/src/Cli/CliCommands.php @@ -0,0 +1,74 @@ +] + */ +final class CliCommands +{ + /** Clear the page cache. Pass --network to flush every blog. */ + public function flush(array $args, array $assoc): void + { + $keep = ! empty((new SettingsService())->get('cache')['keep_assets']); + $network = ! empty($assoc['network']); + (new CacheStore())->clear($keep, $network); + WP_CLI::success($network + ? 'WP Performance cache cleared for the whole network.' + : 'WP Performance cache cleared.'); + } + + /** Flush the block (fragment) cache. */ + public function flushBlocks(array $args, array $assoc): void + { + (new FragmentStore())->flush(); + WP_CLI::success('WP Performance block cache flushed.'); + } + + /** Enable WP Performance. */ + public function enable(array $args, array $assoc): void + { + update_option('wpp_disabled', false); + (new RuntimeSettings(new SettingsService()))->write(); + WP_CLI::success('WP Performance enabled.'); + } + + /** Temporarily disable WP Performance. */ + public function disable(array $args, array $assoc): void + { + update_option('wpp_disabled', true); + (new RuntimeSettings(new SettingsService()))->write(); + WP_CLI::success('WP Performance disabled.'); + } + + /** + * Run database cleanup. + * + * ## OPTIONS + * + * [] + * : One of all, trash, spam, revisions, transients, autodrafts, cron. Defaults to all. + */ + public function cleanup(array $args, array $assoc): void + { + $type = $args[0] ?? 'all'; + $valid = ['all', 'trash', 'spam', 'revisions', 'transients', 'autodrafts', 'cron']; + + if (! in_array($type, $valid, true)) { + WP_CLI::error('Invalid type. Use one of: ' . implode(', ', $valid)); + return; + } + + (new DatabaseService())->clear($type); + WP_CLI::success("Database cleanup ({$type}) complete."); + } +} diff --git a/src/Core/CoreModule.php b/src/Core/CoreModule.php new file mode 100644 index 0000000..7419871 --- /dev/null +++ b/src/Core/CoreModule.php @@ -0,0 +1,213 @@ +bind(SettingsService::class, static fn (): SettingsService => new SettingsService()); + $container->bind(DatabaseService::class, static fn (): DatabaseService => new DatabaseService()); + $container->bind(CacheStore::class, static fn (): CacheStore => new CacheStore()); + $container->bind(FragmentStore::class, static fn (): FragmentStore => new FragmentStore()); + $container->bind( + FragmentCache::class, + static fn (Container $c): FragmentCache => new FragmentCache( + $c->get(SettingsService::class), + $c->get(FragmentStore::class) + ) + ); + $container->bind( + RuntimeSettings::class, + static fn (Container $c): RuntimeSettings => new RuntimeSettings($c->get(SettingsService::class)) + ); + $container->bind(Minifier::class, static fn (): Minifier => new Minifier()); + $container->bind(HtmlOptimizer::class, static fn (): HtmlOptimizer => new HtmlOptimizer()); + $container->bind(Collection::class, static fn (): Collection => new Collection()); + $container->bind(ImageService::class, static fn (): ImageService => new ImageService()); + $container->bind(ImageConverter::class, static fn (): ImageConverter => new ImageConverter()); + $container->bind(ServerRules::class, static fn (): ServerRules => new ServerRules()); + $container->bind( + Preloader::class, + static fn (Container $c): Preloader => new Preloader($c->get(SettingsService::class)) + ); + $container->bind(FontHost::class, static fn (): FontHost => new FontHost()); + $container->bind(AssetParser::class, static fn (Container $c): AssetParser => new AssetParser( + $c->get(SettingsService::class), + $c->get(Minifier::class), + $c->get(HtmlOptimizer::class), + $c->get(Collection::class), + $c->get(FontHost::class) + )); + + $settings = $container->get(SettingsService::class); + $store = $container->get(CacheStore::class); + + $history = new SettingsHistory($settings); + $history->register(); + + $logger = new Logger($settings); + $logger->register(); + + $fragmentStore = $container->get(FragmentStore::class); + $container->get(FragmentCache::class)->register(); + add_action('wpp.cache.after_clear', static function () use ($settings, $fragmentStore): void { + // The purge deletes the directory's .htaccess along with the cache. + Plugin::protectCacheDir(); + + if (! empty($settings->get('cache')['block_cache_flush_on_clear'])) { + $fragmentStore->flush(); + } + }); + + add_action('init', static function (): void { + $asset = WPP_DIR . 'build/blocks/cache/index.asset.php'; + if (! file_exists($asset)) { + return; + } + $data = require $asset; + wp_register_script( + 'wpp-cache-block', + WPP_URL . 'build/blocks/cache/index.js', + $data['dependencies'], + $data['version'], + true + ); + wp_set_script_translations('wpp-cache-block', 'wpp', WPP_DIR . 'languages'); + register_block_type('wpp/cache', ['editor_script' => 'wpp-cache-block']); + }); + + (new RestProvider( + new SettingsController($settings), + new DatabaseController($container->get(DatabaseService::class)), + new CacheController($store, $settings, $fragmentStore), + new FilesController($container->get(Collection::class), $store), + new ToolsController($settings, new Presets(), $history, $logger), + new ImageController($container->get(ImageService::class), $container->get(ImageConverter::class)), + new ServerController($container->get(ServerRules::class), $settings), + new OverviewController($store, $settings, $container->get(ServerRules::class), $fragmentStore), + ))->register(); + + (new CacheInvalidation($settings, $store, $container->get(RuntimeSettings::class), $fragmentStore))->register(); + (new MediaHooks($settings, $container->get(ImageService::class), $container->get(ImageConverter::class)))->register(); + (new CronHooks($settings, $container->get(DatabaseService::class), $container->get(Preloader::class)))->register(); + + $serverRules = $container->get(ServerRules::class); + add_action('wpp.settings.updated', static function (string $group) use ($serverRules, $settings): void { + if ($group === 'cache') { + $serverRules->apply($settings->get('cache')); + } + if ($group === 'tools') { + $objectCache = new ObjectCacheInstaller(); + $want = ! empty($settings->get('tools')['object_cache']) && $objectCache->available(); + if ($want && ! $objectCache->installed()) { + // Turn the setting back off if another drop-in owns the file, + // so the toggle never reads ON while nothing was installed. + if (! $objectCache->install()) { + $settings->update('tools', ['object_cache' => false]); + } + } elseif (! $want && $objectCache->installed()) { + $objectCache->uninstall(); + } + } + }, 10, 1); + + if (is_admin()) { + (new AdminMenu())->register(); + (new AdminAssets($settings))->register(); + (new Metabox())->register(); + (new CompatibilityNotice())->register(); + + // Migrate legacy options. The activation hook does not fire on a plugin + // update (WordPress reactivates silently), so an existing user who simply + // updates would never be migrated by activation alone. Run it here too, + // flag-gated so it is a no-op after the first pass. + add_action('admin_init', static function () use ($settings): void { + (new Migration($settings))->maybeRun(); + }); + + // Self-heal: activation only runs once, so restore anything the + // drop-in needs if it went missing. Without the runtime file the + // drop-in bails and page caching stops without any visible sign. + Plugin::protectCacheDir(); + + $dropin = new DropinInstaller(); + $runtime = $container->get(RuntimeSettings::class); + // Both files are version stamped, so a rewrite here means this is the + // first admin request after an update. + $updated = false; + if (! defined('WP_CACHE') || ! $dropin->dropinInstalled()) { + $dropin->install(); + $runtime->write(); + $updated = true; + } elseif (! $runtime->written()) { + $runtime->write(); + $updated = true; + } + + // Deleting the pre-guard config would stop page caching outright if + // the drop-in still reading it could not be refreshed, so this waits + // for confirmation that the installed one looks for the new name. + if ($updated && $dropin->dropinInstalled()) { + Plugin::purgeUnguarded(); + } + } else { + (new PageCache($settings, $store))->register(); + (new Optimizer($container->get(AssetParser::class)))->register(); + } + } +} diff --git a/src/Cron/CronHooks.php b/src/Cron/CronHooks.php new file mode 100644 index 0000000..53cf2fd --- /dev/null +++ b/src/Cron/CronHooks.php @@ -0,0 +1,120 @@ + 'addSchedules']; + } + + protected function actions(): array + { + return [ + 'init' => 'sync', + self::PRELOAD => 'runPreload', + self::DB => 'runDbCleanup', + 'wpp.settings.updated' => ['onSettingsUpdated', 10, 1], + ]; + } + + /** @param array $schedules */ + public function addSchedules(array $schedules): array + { + $schedules['wpp_weekly'] = ['interval' => WEEK_IN_SECONDS, 'display' => __('Once weekly', 'wpp')]; + $schedules['wpp_monthly'] = ['interval' => MONTH_IN_SECONDS, 'display' => __('Once monthly', 'wpp')]; + return $schedules; + } + + public function sync(): void + { + $sitemaps = array_filter((array) $this->settings->get('cache')['sitemaps']); + if ($sitemaps !== [] && ! wp_next_scheduled(self::PRELOAD)) { + wp_schedule_event(time() + 300, 'hourly', self::PRELOAD); + } elseif ($sitemaps === [] && wp_next_scheduled(self::PRELOAD)) { + wp_clear_scheduled_hook(self::PRELOAD); + } + + $recurrence = $this->recurrence((string) ($this->settings->get('database')['frequency'] ?? 'none')); + $current = wp_get_schedule(self::DB); + + if ($recurrence !== null && $current !== $recurrence) { + wp_clear_scheduled_hook(self::DB); + wp_schedule_event(time() + HOUR_IN_SECONDS, $recurrence, self::DB); + $this->updateNextRun(); + } elseif ($recurrence === null && $current !== false) { + wp_clear_scheduled_hook(self::DB); + delete_option('wpp_db_cleanup_next'); + } + } + + public function onSettingsUpdated(string $group): void + { + if ($group === 'cache' || $group === 'database') { + $this->sync(); + } + } + + public function runPreload(): void + { + $this->preloader->run(); + } + + public function runDbCleanup(): void + { + $db = $this->settings->get('database'); + $map = [ + 'cleanup_trash' => 'trash', + 'cleanup_spam' => 'spam', + 'cleanup_revisions' => 'revisions', + 'cleanup_transients' => 'transients', + 'cleanup_autodrafts' => 'autodrafts', + 'cleanup_cron' => 'cron', + ]; + foreach ($map as $flag => $type) { + if (! empty($db[$flag])) { + $this->database->clear($type); + } + } + $this->updateNextRun(); + } + + private function recurrence(string $frequency): ?string + { + return match ($frequency) { + 'daily' => 'daily', + 'weekly' => 'wpp_weekly', + 'monthly' => 'wpp_monthly', + default => null, + }; + } + + private function updateNextRun(): void + { + $next = wp_next_scheduled(self::DB); + if ($next) { + update_option('wpp_db_cleanup_next', $next, false); + } + } +} diff --git a/src/Cron/Preloader.php b/src/Cron/Preloader.php new file mode 100644 index 0000000..68d6e54 --- /dev/null +++ b/src/Cron/Preloader.php @@ -0,0 +1,92 @@ +settings->get('cache')['sitemaps']); + if ($sitemaps === []) { + return; + } + + $pages = []; + $children = []; + + foreach ($sitemaps as $sitemap) { + $body = $this->fetch((string) $sitemap); + if ($body === '') { + continue; + } + // The URLs admins configure are usually indexes (wp-sitemap.xml, + // sitemap_index.xml), whose entries are further sitemaps. + if (stripos($body, 'locations($body)); + } else { + $pages = array_merge($pages, $this->locations($body)); + } + } + + $children = array_slice(array_values(array_unique($children)), 0, self::MAX_INDEXED); + foreach ($children as $child) { + if (count($pages) >= self::MAX_URLS) { + break; + } + $body = $this->fetch($child); + if ($body !== '') { + $pages = array_merge($pages, $this->locations($body)); + } + } + + $pages = array_slice(array_values(array_unique($pages)), 0, self::MAX_URLS); + foreach ($pages as $url) { + wp_remote_get($url, ['timeout' => 5, 'blocking' => false, 'reject_unsafe_urls' => true]); + } + } + + private function fetch(string $url): string + { + $response = wp_remote_get($url, ['timeout' => 10, 'reject_unsafe_urls' => true]); + return is_wp_error($response) ? '' : (string) wp_remote_retrieve_body($response); + } + + /** + * Sitemap bodies are remote input, so only locations on this site are kept: + * anything else would let a third-party sitemap aim requests at hosts the + * site can reach but the internet cannot. + * + * @return list + */ + private function locations(string $body): array + { + if (! preg_match_all('#\s*(.*?)\s*#i', $body, $matches)) { + return []; + } + + $host = strtolower((string) wp_parse_url(home_url(), PHP_URL_HOST)); + $out = []; + foreach ($matches[1] as $loc) { + $loc = trim((string) $loc); + if ($loc !== '' && strtolower((string) wp_parse_url($loc, PHP_URL_HOST)) === $host) { + $out[] = $loc; + } + } + + return $out; + } +} diff --git a/src/Database/DatabaseService.php b/src/Database/DatabaseService.php new file mode 100644 index 0000000..51f7d3d --- /dev/null +++ b/src/Database/DatabaseService.php @@ -0,0 +1,188 @@ + */ + public function counts(): array + { + return [ + 'trash' => $this->trashCount(), + 'spam' => $this->spamCount(), + 'revisions' => $this->revisionsCount(), + 'transients' => $this->transientsCount(), + 'autodrafts' => $this->autoDraftsCount(), + 'cron' => $this->cronCount(), + ]; + } + + public function clear(string $type): void + { + match ($type) { + 'trash' => $this->clearTrash(), + 'spam' => $this->clearSpam(), + 'revisions' => $this->clearRevisions(), + 'transients' => $this->clearTransients(), + 'autodrafts' => $this->clearAutoDrafts(), + 'cron' => $this->clearCron(), + 'all' => $this->clearAll(), + default => null, + }; + + do_action('wpp.db.cleaned', $type); + } + + public function clearAll(): void + { + $this->clearTrash(); + $this->clearSpam(); + $this->clearRevisions(); + $this->clearTransients(); + $this->clearAutoDrafts(); + $this->clearCron(); + } + + private function revisionsCount(): int + { + global $wpdb; + return (int) $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->posts} WHERE post_type = 'revision'"); + } + + private function clearRevisions(): void + { + global $wpdb; + $wpdb->query("DELETE FROM {$wpdb->posts} WHERE post_type = 'revision'"); + } + + private function autoDraftsCount(): int + { + global $wpdb; + return (int) $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->posts} WHERE post_status = 'auto-draft'"); + } + + private function clearAutoDrafts(): void + { + global $wpdb; + $wpdb->query("DELETE FROM {$wpdb->posts} WHERE post_status = 'auto-draft'"); + } + + private function trashCount(): int + { + global $wpdb; + return (int) $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->posts} WHERE post_status = 'trash'"); + } + + private function clearTrash(): void + { + global $wpdb; + $wpdb->query("DELETE FROM {$wpdb->posts} WHERE post_status = 'trash'"); + } + + private function spamCount(): int + { + global $wpdb; + return (int) $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->comments} WHERE comment_approved IN ('spam', 'trash')"); + } + + private function clearSpam(): void + { + global $wpdb; + $wpdb->query("DELETE FROM {$wpdb->comments} WHERE comment_approved IN ('spam', 'trash')"); + } + + /** Value rows only: an expiring transient also stores a _timeout_ row. */ + private function transientsCount(): int + { + global $wpdb; + return (int) $wpdb->get_var( + $wpdb->prepare( + "SELECT COUNT(*) FROM {$wpdb->options} + WHERE (option_name LIKE %s OR option_name LIKE %s) + AND option_name NOT LIKE %s + AND option_name NOT LIKE %s", + $wpdb->esc_like('_transient_') . '%', + $wpdb->esc_like('_site_transient_') . '%', + $wpdb->esc_like('_transient_timeout_') . '%', + $wpdb->esc_like('_site_transient_timeout_') . '%' + ) + ); + } + + /** + * Expired transients only. Deleting every match would drop live caches and + * non-expiring transients that other plugins rely on. + */ + private function clearTransients(): void + { + global $wpdb; + $expired = (array) $wpdb->get_col( + $wpdb->prepare( + "SELECT option_name FROM {$wpdb->options} + WHERE (option_name LIKE %s OR option_name LIKE %s) + AND option_value < %d", + $wpdb->esc_like('_transient_timeout_') . '%', + $wpdb->esc_like('_site_transient_timeout_') . '%', + time() + ) + ); + + $names = []; + foreach ($expired as $timeout) { + $timeout = (string) $timeout; + $names[] = $timeout; + $names[] = str_starts_with($timeout, '_site_transient_timeout_') + ? '_site_transient_' . substr($timeout, 24) + : '_transient_' . substr($timeout, 19); + } + + foreach (array_chunk($names, 200) as $chunk) { + $placeholders = implode(', ', array_fill(0, count($chunk), '%s')); + $wpdb->query( + $wpdb->prepare( + "DELETE FROM {$wpdb->options} WHERE option_name IN ({$placeholders})", + ...$chunk + ) + ); + } + } + + private function cronCount(): int + { + $count = 0; + foreach ((array) _get_cron_array() as $hooks) { + if (! is_array($hooks)) { + continue; + } + foreach ($hooks as $hook => $events) { + if (! has_action((string) $hook)) { + $count += is_array($events) ? count($events) : 0; + } + } + } + return $count; + } + + private function clearCron(): void + { + foreach ((array) _get_cron_array() as $timestamp => $hooks) { + if (! is_array($hooks)) { + continue; + } + foreach ($hooks as $hook => $events) { + if (has_action((string) $hook) || ! is_array($events)) { + continue; + } + foreach ($events as $event) { + wp_unschedule_event($timestamp, (string) $hook, $event['args'] ?? []); + } + } + } + } +} diff --git a/src/Foundation/Container/Container.php b/src/Foundation/Container/Container.php new file mode 100644 index 0000000..3cb93e0 --- /dev/null +++ b/src/Foundation/Container/Container.php @@ -0,0 +1,61 @@ + */ + private array $bindings = []; + + /** @var array */ + private array $instances = []; + + /** Factory receives the container so it can resolve collaborators. */ + public function bind(string $id, Closure $factory): void + { + $this->bindings[$id] = $factory; + unset($this->instances[$id]); + } + + /** Register an already-constructed instance. */ + public function instance(string $id, object $instance): void + { + $this->instances[$id] = $instance; + } + + public function has(string $id): bool + { + return isset($this->bindings[$id]) || isset($this->instances[$id]); + } + + /** + * @template T of object + * @param class-string|string $id + * @return T|object + */ + public function get(string $id): object + { + if (isset($this->instances[$id])) { + return $this->instances[$id]; + } + + if (! isset($this->bindings[$id])) { + throw new RuntimeException("WP Performance container: no binding registered for {$id}"); + } + + $instance = ($this->bindings[$id])($this); + $this->instances[$id] = $instance; + + return $instance; + } +} diff --git a/src/Foundation/Helpers/View.php b/src/Foundation/Helpers/View.php new file mode 100644 index 0000000..76ad51f --- /dev/null +++ b/src/Foundation/Helpers/View.php @@ -0,0 +1,62 @@ + + */ + protected function actions(): array + { + return []; + } + + /** @return array */ + protected function filters(): array + { + return []; + } + + public function register(): void + { + foreach ($this->actions() as $hook => $spec) { + [$method, $priority, $args] = $this->normalize($spec); + add_action($hook, [$this, $method], $priority, $args); + } + + foreach ($this->filters() as $hook => $spec) { + [$method, $priority, $args] = $this->normalize($spec); + add_filter($hook, [$this, $method], $priority, $args); + } + } + + /** Normalise a hook spec to [method, priority, accepted_args]. */ + private function normalize(string|array $spec): array + { + if (is_string($spec)) { + return [$spec, 10, 1]; + } + return [$spec[0], $spec[1] ?? 10, $spec[2] ?? 1]; + } +} diff --git a/src/Foundation/Modules/Module.php b/src/Foundation/Modules/Module.php new file mode 100644 index 0000000..23df6dc --- /dev/null +++ b/src/Foundation/Modules/Module.php @@ -0,0 +1,21 @@ + */ + private array $modules = []; + + /** @var array */ + private array $booted = []; + + public function __construct(private Container $container) + { + } + + public function register(Module $module): void + { + $id = $module->id(); + + if (isset($this->modules[$id])) { + throw new RuntimeException("WP Performance module '{$id}' is already registered."); + } + + $this->modules[$id] = $module; + } + + public function get(string $id): ?Module + { + return $this->modules[$id] ?? null; + } + + /** @return array */ + public function all(): array + { + return $this->modules; + } + + public function bootAll(): void + { + foreach ($this->modules as $id => $module) { + if ($this->booted[$id] ?? false) { + continue; + } + $module->boot($this->container); + $this->booted[$id] = true; + do_action('wpp.module.booted', $id); + } + } +} diff --git a/src/Foundation/Plugin.php b/src/Foundation/Plugin.php new file mode 100644 index 0000000..1330ca9 --- /dev/null +++ b/src/Foundation/Plugin.php @@ -0,0 +1,310 @@ + + + Require all denied + + + Order allow,deny + Deny from all + + + + HTACCESS; + + private static ?self $instance = null; + private static bool $booted = false; + + public readonly Container $container; + public readonly ModuleManager $modules; + + private function __construct() + { + $this->container = new Container(); + $this->modules = new ModuleManager($this->container); + + $this->container->instance(Container::class, $this->container); + $this->container->instance(ModuleManager::class, $this->modules); + } + + public static function instance(): self + { + return self::$instance ??= new self(); + } + + /** Load text domain, register and boot all modules. Idempotent. */ + public static function boot(): void + { + if (self::$booted) { + return; + } + self::$booted = true; + + $self = self::instance(); + + load_plugin_textdomain('wpp', false, dirname(plugin_basename(WPP_FILE)) . '/languages'); + + $self->modules->register(new CoreModule()); + $self->modules->register(new CloudflareModule()); + $self->modules->register(new VarnishModule()); + $self->modules->register(new PrefetchModule()); + + // Allow third-party add-on modules to register here. + do_action('wpp.modules.register', $self->modules); + + $self->modules->bootAll(); + + // The activation hook does not fire on a plugin update, so a copy of + // object-cache.php left by an earlier release would otherwise stay in + // wp-content untouched for good. + add_action('admin_init', static function (): void { + self::syncObjectCache(new SettingsService()); + }); + + do_action('wpp.booted', $self); + } + + public static function onActivation(): void + { + self::protectCacheDir(); + + $settings = new SettingsService(); + + self::bootAddons(); + (new Migration($settings))->maybeRun(); + + $dropin = new DropinInstaller(); + $dropin->install(); + self::syncObjectCache($settings); + (new RuntimeSettings($settings))->write(); + (new ServerRules())->apply($settings->get('cache')); + + // Deleting the pre-guard files would strand a drop-in that still reads + // them, so this waits for confirmation that ours is the one installed. + if ($dropin->dropinInstalled()) { + self::purgeUnguarded(); + } + + do_action('wpp.activated'); + } + + /** @param bool $networkWide as register_deactivation_hook passes it */ + public static function onDeactivation(bool $networkWide = false): void + { + // Whatever happens to the shared files, this blog has to stop being + // served from cache. The stored settings are left alone so that + // reactivating restores them. + self::disableRuntime(new RuntimeSettings(new SettingsService())); + + // advanced-cache.php, object-cache.php, wp-config.php, the cache + // directory and the root .htaccess are all network-wide. Tearing them + // down would stop caching for every other blog still using the plugin. + // + // A network deactivation leaves no blog with the plugin active, and + // WordPress writes active_sitewide_plugins only after this hook has + // run, so the sitewide check cannot answer for it. + if ($networkWide || ! self::activeOnAnotherBlog()) { + (new DropinInstaller())->uninstall(); + (new ObjectCacheInstaller())->uninstall(); + (new CacheStore())->clear(false, true); + (new ServerRules())->removeAll(); + } else { + // Only this blog's pages: the assets and the other blogs' pages + // belong to the sites still running the plugin. + (new CacheStore())->clear(true); + } + + wp_clear_scheduled_hook('wpp_preload'); + wp_clear_scheduled_hook('wpp_db_cleanup'); + + do_action('wpp.deactivated'); + } + + /** Flip the file the drop-in reads without touching the stored settings. */ + private static function disableRuntime(RuntimeSettings $runtime): void + { + $file = $runtime->file(); + if (is_file($file)) { + @file_put_contents($file, RuntimeSettings::GUARD . (string) wp_json_encode(['enabled' => false]), LOCK_EX); + } + } + + /** + * The cache directory sits in the web root. The troubleshooting log and the + * drop-in's runtime JSON hold request paths and the cache exclusion list, + * so neither may be fetchable over HTTP. + */ + public static function protectCacheDir(): void + { + if (! is_dir(WPP_CACHE_DIR) && ! wp_mkdir_p(WPP_CACHE_DIR)) { + return; + } + + $index = WPP_CACHE_DIR . 'index.php'; + if (! is_file($index)) { + @file_put_contents($index, " + */ + private static function unguardedFiles(): array + { + if (! is_multisite()) { + return array_merge( + glob(WPP_CACHE_DIR . '*wpp.log') ?: [], + glob(WPP_CACHE_DIR . '*.json') ?: [] + ); + } + + $settings = new SettingsService(); + $host = CacheStore::sanitizeHost((string) parse_url((string) home_url(), PHP_URL_HOST)); + + return [ + substr((new RuntimeSettings($settings))->file(), 0, -4), + substr((new Logger($settings))->file(), 0, -4), + WPP_CACHE_DIR . $host . '.settings.json', + ]; + } + + /** + * Activation runs after plugins_loaded, so boot() never fired and the add-on + * modules have not registered their settings groups. Migrating without them + * would treat the legacy Cloudflare/Varnish/Prefetch options as orphans. + */ + private static function bootAddons(): void + { + if (self::$booted) { + return; + } + + $self = self::instance(); + + if (! $self->container->has(SettingsService::class)) { + $self->container->bind(SettingsService::class, static fn (): SettingsService => new SettingsService()); + } + + foreach ([new CloudflareModule(), new VarnishModule(), new PrefetchModule()] as $module) { + if ($self->modules->get($module->id()) === null) { + $self->modules->register($module); + } + } + + $self->modules->bootAll(); + } + + /** + * Put the object-cache drop-in back after a deactivation removed it, and + * refresh a copy an earlier release installed. + */ + public static function syncObjectCache(SettingsService $settings): void + { + $objectCache = new ObjectCacheInstaller(); + + if (empty($settings->get('tools')['object_cache']) || ! $objectCache->available()) { + return; + } + + if ($objectCache->objectCacheInstalled() || $objectCache->install()) { + return; + } + + // A failed refresh of a copy that still works must not switch the + // toggle off; only nothing of ours on disk means the toggle is lying. + if (! $objectCache->installed()) { + $settings->update('tools', ['object_cache' => false]); + } + } + + /** True when another blog on the network still has the plugin active. */ + private static function activeOnAnotherBlog(): bool + { + if (! is_multisite()) { + return false; + } + + $basename = plugin_basename(WPP_FILE); + $current = get_current_blog_id(); + + if (array_key_exists($basename, (array) get_site_option('active_sitewide_plugins', []))) { + return true; + } + + foreach (get_sites(['fields' => 'ids', 'number' => 0]) as $blogId) { + if ((int) $blogId === $current) { + continue; + } + + switch_to_blog((int) $blogId); + $active = in_array($basename, (array) get_option('active_plugins', []), true); + restore_current_blog(); + + if ($active) { + return true; + } + } + + return false; + } +} diff --git a/src/Frontend/Optimizer.php b/src/Frontend/Optimizer.php new file mode 100644 index 0000000..b470ea7 --- /dev/null +++ b/src/Frontend/Optimizer.php @@ -0,0 +1,29 @@ + ['optimize', 20, 1]]; + } + + public function optimize(string $html): string + { + return $this->parser->parse($html); + } +} diff --git a/src/Frontend/PageCache.php b/src/Frontend/PageCache.php new file mode 100644 index 0000000..476b550 --- /dev/null +++ b/src/Frontend/PageCache.php @@ -0,0 +1,287 @@ + ['startBuffer', 0]]; + } + + public function startBuffer(): void + { + if (! $this->shouldBuffer()) { + return; + } + $this->started = microtime(true); + ob_start([$this, 'finish']); + } + + public function finish(string $html): string + { + if (strlen($html) < 255 || http_response_code() !== 200) { + return $html; + } + + $html = (string) apply_filters('wpp.frontend.html', $html); + + $seconds = $this->started > 0 ? round(microtime(true) - $this->started, 3) : 0; + $cached = $this->cacheApplies(); + + $html .= $cached + ? sprintf("\n", $seconds, gmdate('Y-m-d H:i:s')) + : sprintf("\n", $seconds); + + // Re-checked after rendering: a template or plugin can set DONOTCACHEPAGE + // while the page is being built, long after startBuffer() ran. + if ($cached && defined('DONOTCACHEPAGE') && DONOTCACHEPAGE) { + $cached = false; + } + + if ($cached) { + $cache = $this->settings->get('cache'); + $host = CacheStore::sanitizeHost((string) parse_url(home_url(), PHP_URL_HOST)); + $permalinks = (bool) get_option('permalink_structure'); + $mobile = ! empty($cache['mobile']) && wp_is_mobile(); + $file = CacheStore::fileFor($host, $_SERVER['REQUEST_URI'] ?? '/', $permalinks, $mobile); + $this->store->save($file, $html, ! empty($cache['gzip'])); + do_action('wpp.cache.saved', $_SERVER['REQUEST_URI'] ?? '/'); + } + + return $html; + } + + private function shouldBuffer(): bool + { + if (is_admin() || wp_doing_ajax() || wp_doing_cron() || (defined('REST_REQUEST') && REST_REQUEST)) { + return false; + } + if (defined('DONOTCACHEPAGE') && DONOTCACHEPAGE) { + return false; + } + if (! empty($_POST)) { + return false; + } + if (is_404() || is_search() || is_feed() || is_preview() || is_trackback()) { + return false; + } + + return $this->cacheApplies() || $this->optimizationActive(); + } + + private function cacheApplies(): bool + { + $cache = $this->settings->get('cache'); + if (empty($cache['enabled']) || is_user_logged_in()) { + return false; + } + + // The drop-in stops serving while this is set, so writes must stop too: + // otherwise `wp wpp disable` fills the cache with debug-state renders + // that get fresh mtimes and are served the moment it is lifted. + if (get_option('wpp_disabled', false)) { + return false; + } + + // Password-protected content must never reach the shared anonymous + // cache: the visitor who entered the password renders the unlocked page, + // and everyone else would then be served it straight from disk. + if ($this->passwordSession() || (is_singular() && post_password_required())) { + return false; + } + + // Core prefills the comment form from these cookies, so a commenter's + // render carries their name, email and URL, plus the moderation notices + // on their own pending comments. The drop-in refuses to serve cache to + // that session; without the same check here it is that session's render + // the drop-in then hands to everyone else. + if ($this->commenterSession()) { + return false; + } + + // Only cache real HTML. Sitemaps and other XML/JSON responses would be + // replayed by the drop-in with a text/html content type. + if (! $this->isHtmlResponse()) { + return false; + } + + if (empty($cache['cache_query_strings']) + && CacheStore::hasRealQuery((string) parse_url($_SERVER['REQUEST_URI'] ?? '', PHP_URL_QUERY)) + ) { + return false; + } + + if ($this->isEcommercePage() || $this->hasCartCookie()) { + return false; + } + + $current = (is_ssl() ? 'https' : 'http') . '://' + . ($_SERVER['HTTP_HOST'] ?? '') . ($_SERVER['REQUEST_URI'] ?? ''); + + if (Url::anyMatch((array) ($cache['exclude_urls'] ?? []), $current)) { + return false; + } + + $ua = (string) ($_SERVER['HTTP_USER_AGENT'] ?? ''); + + if (! empty($cache['exclude_search_bots']) + && preg_match('/bot|crawl|slurp|spider|bing|google|yandex|duckduck/i', $ua) + ) { + return false; + } + + // Also enforced on the write path. The drop-in refuses to serve an + // excluded agent, but without this its render would still be the copy + // written to disk and handed to everyone else. + foreach ((array) ($cache['exclude_user_agents'] ?? []) as $pattern) { + $pattern = trim((string) $pattern); + if ($pattern !== '' && stripos($ua, $pattern) !== false) { + return false; + } + } + + if (is_singular()) { + $id = get_queried_object_id(); + if ($id && get_post_meta($id, '_wpp_exclude_cache', true)) { + return false; + } + } + + return true; + } + + /** A visitor holding a post-password cookie renders unlocked content. */ + private function passwordSession(): bool + { + foreach (array_keys($_COOKIE) as $cookie) { + if (str_starts_with((string) $cookie, 'wp-postpass_')) { + return true; + } + } + return false; + } + + /** A visitor holding comment-author cookies renders a personalised page. */ + private function commenterSession(): bool + { + foreach (array_keys($_COOKIE) as $cookie) { + if (str_starts_with((string) $cookie, 'comment_author_')) { + return true; + } + } + return false; + } + + private function isHtmlResponse(): bool + { + if (is_feed() || is_embed()) { + return false; + } + + foreach (headers_list() as $header) { + if (stripos($header, 'content-type:') !== 0) { + continue; + } + return stripos($header, 'text/html') !== false; + } + + return true; + } + + private function isEcommercePage(): bool + { + if (function_exists('is_woocommerce')) { + if ((function_exists('is_cart') && is_cart()) + || (function_exists('is_checkout') && is_checkout()) + || (function_exists('is_account_page') && is_account_page()) + ) { + return true; + } + } + return function_exists('edd_is_checkout') && edd_is_checkout(); + } + + private function hasCartCookie(): bool + { + foreach (array_keys($_COOKIE) as $cookie) { + if (preg_match('/^(woocommerce_items_in_cart|woocommerce_cart_hash|wp_woocommerce_session_|edd_items_in_cart|edd_cart_token)/', (string) $cookie)) { + return true; + } + } + return false; + } + + /** + * Must list every option AssetParser acts on: the parser only ever runs + * through the filter this buffer applies, so an option missing here is an + * option that silently does nothing whenever page caching does not apply. + */ + private function optimizationActive(): bool + { + $css = $this->settings->get('css'); + $js = $this->settings->get('js'); + $html = $this->settings->get('html'); + $media = $this->settings->get('media'); + $cdn = $this->settings->get('cdn'); + + if (! empty($html['enabled']) || ! empty($cdn['enabled'])) { + return true; + } + + foreach (['defer', 'minify_inline', 'remove_unused', 'combine_fonts', 'host_fonts'] as $flag) { + if (! empty($css[$flag])) { + return true; + } + } + if ((string) ($css['font_display'] ?? 'none') !== 'none') { + return true; + } + foreach (['dns_prefetch', 'preconnect'] as $hints) { + if (array_filter((array) ($css[$hints] ?? [])) !== []) { + return true; + } + } + + if (! empty($js['defer']) || ! empty($js['delay']) || ! empty($js['minify_inline'])) { + return true; + } + + if (! empty($media['images_lazy']) || ! empty($media['images_responsive']) + || ! empty($media['videos_lazy']) || ! empty($media['images_dimensions']) + || ! empty($media['webp']) || (int) ($media['lcp_images'] ?? 0) > 0 + ) { + return true; + } + + foreach (['minify', 'combine', 'inline', 'disable'] as $map) { + if (array_filter((array) ($css[$map] ?? [])) !== [] + || array_filter((array) ($js[$map] ?? [])) !== [] + ) { + return true; + } + } + + return false; + } +} diff --git a/src/Media/ImageConverter.php b/src/Media/ImageConverter.php new file mode 100644 index 0000000..38d77b9 --- /dev/null +++ b/src/Media/ImageConverter.php @@ -0,0 +1,148 @@ + image.jpg.webp. + */ +final class ImageConverter +{ + public function supportsWebp(): bool + { + return function_exists('imagewebp'); + } + + public function supportsAvif(): bool + { + return function_exists('imageavif'); + } + + /** + * Convert one image file. Returns the formats produced. + * + * @return string[] + */ + public function convert(string $path): array + { + if (! is_file($path)) { + return []; + } + $ext = strtolower(pathinfo($path, PATHINFO_EXTENSION)); + if (! in_array($ext, ['jpg', 'jpeg', 'png'], true)) { + return []; + } + + $image = $ext === 'png' ? @imagecreatefrompng($path) : @imagecreatefromjpeg($path); + if (! $image) { + return []; + } + if ($ext === 'png') { + imagepalettetotruecolor($image); + imagealphablending($image, false); + imagesavealpha($image, true); + } + + $made = []; + if ($this->supportsAvif() && $this->missing($path . '.avif') && $this->encode('avif', $image, $path . '.avif')) { + $made[] = 'avif'; + } + if ($this->supportsWebp() && $this->missing($path . '.webp') && $this->encode('webp', $image, $path . '.webp')) { + $made[] = 'webp'; + } + + imagedestroy($image); + return $made; + } + + /** A zero-byte output is a failed encode from an earlier run, so retry it. */ + private function missing(string $file): bool + { + clearstatcache(true, $file); + + return ! is_file($file) || (int) @filesize($file) === 0; + } + + /** + * GD creates the destination before it encodes, so an encode that runs out + * of memory or is killed leaves a truncated file behind. Nothing would ever + * remove it and every AVIF-capable browser would pick it over the original, + * so the output is only moved into place once it is known to be complete. + */ + private function encode(string $format, GdImage $image, string $dest): bool + { + $tmp = $dest . '.tmp'; + + $ok = $format === 'avif' + ? @imageavif($image, $tmp, 70) + : @imagewebp($image, $tmp, 82); + + clearstatcache(true, $tmp); + + if ($ok && is_file($tmp) && (int) @filesize($tmp) > 0 && @rename($tmp, $dest)) { + return true; + } + + @unlink($tmp); + return false; + } + + /** Convert every size file of an attachment. */ + public function convertAttachment(int $id): void + { + $file = get_attached_file($id); + if (! $file) { + return; + } + $this->convert($file); + + $meta = wp_get_attachment_metadata($id); + if (! empty($meta['sizes']) && is_array($meta['sizes'])) { + $dir = dirname($file); + foreach ($meta['sizes'] as $size) { + if (! empty($size['file'])) { + $this->convert($dir . '/' . $size['file']); + } + } + } + } + + /** + * Convert a slice of image attachments. + * + * @return array{processed:int,total:int,done:bool} + */ + public function bulk(int $offset, int $limit): array + { + $query = new WP_Query([ + 'post_type' => 'attachment', + 'post_mime_type' => ['image/jpeg', 'image/png'], + 'post_status' => 'inherit', + 'fields' => 'ids', + 'posts_per_page' => $limit, + 'offset' => $offset, + 'orderby' => 'ID', + 'order' => 'ASC', + ]); + + /** @var int[] $ids */ + $ids = $query->posts; + foreach ($ids as $id) { + $this->convertAttachment($id); + } + + $total = (int) $query->found_posts; + $processed = $offset + count($ids); + + return [ + 'processed' => $processed, + 'total' => $total, + 'done' => count($ids) === 0 || $processed >= $total, + ]; + } +} diff --git a/src/Media/ImageService.php b/src/Media/ImageService.php new file mode 100644 index 0000000..2c743a4 --- /dev/null +++ b/src/Media/ImageService.php @@ -0,0 +1,183 @@ +custom() as $name => $size) { + add_image_size((string) $name, (int) $size['width'], (int) $size['height'], (bool) $size['crop']); + } + } + + /** + * Drop removed sizes during attachment metadata generation. + * + * @param array $sizes + * @return array + */ + public function filterSizes(array $sizes): array + { + foreach ($this->removed() as $name) { + unset($sizes[$name]); + } + return $sizes; + } + + /** @return list */ + public function definedSizes(): array + { + global $_wp_additional_image_sizes; + + $removed = $this->removed(); + $custom = $this->custom(); + $out = []; + + foreach (self::CORE_SIZES as $name) { + if (in_array($name, $removed, true)) { + continue; + } + $out[] = [ + 'name' => $name, + 'width' => (int) get_option($name . '_size_w'), + 'height' => (int) get_option($name . '_size_h'), + 'crop' => (bool) get_option($name . '_crop'), + 'core' => true, + ]; + } + + if (is_array($_wp_additional_image_sizes)) { + foreach ($_wp_additional_image_sizes as $name => $size) { + if (in_array($name, $removed, true)) { + continue; + } + $out[] = [ + 'name' => (string) $name, + 'width' => (int) $size['width'], + 'height' => (int) $size['height'], + 'crop' => (bool) $size['crop'], + 'core' => ! isset($custom[$name]), + ]; + } + } + + return $out; + } + + public function add(string $name, int $width, int $height, bool $crop): void + { + $name = sanitize_key($name); + if ($name === '') { + return; + } + $custom = $this->custom(); + $custom[$name] = ['width' => $width, 'height' => $height, 'crop' => $crop]; + update_option(self::OPT_CUSTOM, $custom, false); + $this->setRemoved(array_values(array_diff($this->removed(), [$name]))); + + // $_wp_additional_image_sizes is filled once, on init, so the rest of + // this request - definedSizes() included - only sees the change here. + add_image_size($name, $width, $height, $crop); + } + + public function remove(string $name): void + { + $custom = $this->custom(); + if (isset($custom[$name])) { + unset($custom[$name]); + update_option(self::OPT_CUSTOM, $custom, false); + remove_image_size($name); + return; + } + $removed = $this->removed(); + $removed[] = $name; + $this->setRemoved(array_values(array_unique($removed))); + } + + public function restore(): void + { + foreach (array_keys($this->custom()) as $name) { + remove_image_size((string) $name); + } + delete_option(self::OPT_CUSTOM); + delete_option(self::OPT_REMOVED); + } + + /** + * Regenerate a slice of image attachments. + * + * @return array{processed:int,total:int,done:bool} + */ + public function regenerate(int $offset, int $limit): array + { + require_once ABSPATH . 'wp-admin/includes/image.php'; + + $query = new WP_Query([ + 'post_type' => 'attachment', + 'post_mime_type' => 'image', + 'post_status' => 'inherit', + 'fields' => 'ids', + 'posts_per_page' => $limit, + 'offset' => $offset, + 'orderby' => 'ID', + 'order' => 'ASC', + 'no_found_rows' => false, + ]); + + /** @var int[] $ids */ + $ids = $query->posts; + + foreach ($ids as $id) { + $file = get_attached_file($id); + if ($file && file_exists($file)) { + $meta = wp_generate_attachment_metadata($id, $file); + if (! is_wp_error($meta)) { + wp_update_attachment_metadata($id, $meta); + } + } + } + + $total = (int) $query->found_posts; + $processed = $offset + count($ids); + + return [ + 'processed' => $processed, + 'total' => $total, + 'done' => count($ids) === 0 || $processed >= $total, + ]; + } + + /** @return array */ + private function custom(): array + { + $value = get_option(self::OPT_CUSTOM, []); + return is_array($value) ? $value : []; + } + + /** @return string[] */ + private function removed(): array + { + $value = get_option(self::OPT_REMOVED, []); + return is_array($value) ? $value : []; + } + + /** @param string[] $removed */ + private function setRemoved(array $removed): void + { + update_option(self::OPT_REMOVED, $removed, false); + } +} diff --git a/src/Media/MediaHooks.php b/src/Media/MediaHooks.php new file mode 100644 index 0000000..aa7087f --- /dev/null +++ b/src/Media/MediaHooks.php @@ -0,0 +1,99 @@ + 'onInit']; + } + + protected function filters(): array + { + return [ + 'intermediate_image_sizes_advanced' => 'filterImageSizes', + 'wp_generate_attachment_metadata' => ['onMetadata', 10, 2], + ]; + } + + /** + * @param array $metadata + * @return array + */ + public function onMetadata(array $metadata, int $attachmentId): array + { + if (! empty($this->settings->get('media')['webp'])) { + $this->converter->convertAttachment($attachmentId); + } + return $metadata; + } + + public function onInit(): void + { + $this->images->register(); + + $media = $this->settings->get('media'); + if (! empty($media['disable_emoji'])) { + $this->disableEmoji(); + } + if (! empty($media['disable_embeds'])) { + $this->disableEmbeds(); + } + } + + /** + * @param array $sizes + * @return array + */ + public function filterImageSizes(array $sizes): array + { + return $this->images->filterSizes($sizes); + } + + private function disableEmoji(): void + { + remove_action('wp_head', 'print_emoji_detection_script', 7); + remove_action('admin_print_scripts', 'print_emoji_detection_script'); + remove_action('wp_print_styles', 'print_emoji_styles'); + remove_action('admin_print_styles', 'print_emoji_styles'); + remove_filter('the_content_feed', 'wp_staticize_emoji'); + remove_filter('comment_text_rss', 'wp_staticize_emoji'); + remove_filter('wp_mail', 'wp_staticize_emoji_for_email'); + + add_filter('tiny_mce_plugins', static function ($plugins) { + return is_array($plugins) ? array_diff($plugins, ['wpemoji']) : $plugins; + }); + add_filter('wp_resource_hints', static function ($urls, $relation) { + if ($relation === 'dns-prefetch') { + $urls = array_filter((array) $urls, static fn ($u): bool => ! str_contains((string) $u, 's.w.org')); + } + return $urls; + }, 10, 2); + } + + private function disableEmbeds(): void + { + remove_action('rest_api_init', 'wp_oembed_register_route'); + remove_filter('oembed_dataparse', 'wp_filter_oembed_result', 10); + remove_action('wp_head', 'wp_oembed_add_discovery_links'); + remove_action('wp_head', 'wp_oembed_add_host_js'); + add_filter('embed_oembed_discover', '__return_false'); + } +} diff --git a/src/Optimize/AssetParser.php b/src/Optimize/AssetParser.php new file mode 100644 index 0000000..2fd2c05 --- /dev/null +++ b/src/Optimize/AssetParser.php @@ -0,0 +1,1404 @@ +/'; + $delayed = true; + } else { + $tag = ''; + } + } else { + foreach ($combineJs as $original) { + $tag .= ''; + } + } + $html = $this->placeAnchored($html, self::JS_ANCHOR, $tag, ''); + } + + if ($delayed) { + $html = $this->injectBefore($html, '', $this->loaderScript()); + } + + if (! $excludes['html'] && ! empty($htmlOpt['enabled']) && ! Url::anyMatch((array) ($htmlOpt['exclude_urls'] ?? []), $this->currentUrl)) { + $html = $this->htmlOptimizer->optimize($html, $htmlOpt); + } + + $this->collection->flush(); + + return $html; + } + + /** + * Per-post optimization excludes set via the edit-screen metabox. + * + * @return array{css:bool,js:bool,html:bool,image:bool,video:bool} + */ + private function postExcludes(): array + { + $out = ['css' => false, 'js' => false, 'html' => false, 'image' => false, 'video' => false]; + + if (function_exists('is_singular') && is_singular()) { + $id = get_queried_object_id(); + if ($id) { + foreach (array_keys($out) as $type) { + if (get_post_meta($id, '_wpp_exclude_' . $type, true)) { + $out[$type] = true; + } + } + } + } + + return $out; + } + + /** @param array $cfg */ + private function typeExcluded(array $cfg): bool + { + if ($this->loggedIn && ! empty($cfg['disable_loggedin'])) { + return true; + } + return Url::anyMatch((array) ($cfg['exclude_urls'] ?? []), $this->currentUrl); + } + + /** + * @param array $css + * @param array $cdn + * @param array $combine grouped by media value + * @param array $googleFonts grouped by API endpoint + * @param string[] $usedUrls + */ + private function processCss(string $html, array $css, array $cdn, array &$combine, array &$googleFonts, array &$usedUrls): string + { + $anchored = false; + + $result = preg_replace_callback('#])*>#i', function (array $m) use ($css, $cdn, &$combine, &$googleFonts, &$usedUrls, &$anchored): string { + $attrs = $this->parseAttrs($m[0]); + $rel = preg_split('/\s+/', strtolower(trim((string) ($attrs['rel'] ?? '')))) ?: []; + $href = (string) ($attrs['href'] ?? ''); + + // rel="alternate stylesheet" is a sheet the browser leaves disabled. + if (! in_array('stylesheet', $rel, true) || in_array('alternate', $rel, true) + || $href === '' || str_contains($href, '/wpp-cache/') + ) { + return $m[0]; + } + + $local = Assets::isLocal($href); + $key = $this->key($href); + $this->collection->record('css', $this->group($href, $local), $key); + + if ($this->isDisabled($css, $key)) { + return ''; + } + + if (str_contains($href, 'fonts.googleapis.com')) { + return $this->googleFontLink($href, $attrs, $css, $googleFonts, $anchored); + } + + $mediaValue = strtolower(trim((string) ($attrs['media'] ?? ''))); + if ($mediaValue === '') { + $mediaValue = 'all'; + } + + // Only genuine stylesheets may be collected: the href comes from page + // markup, so anything else would be read off disk and re-published. + // A media-scoped sheet is left alone: its rules would otherwise be + // inlined unconditionally. + if (! empty($css['remove_unused']) && $local && $this->isStylesheetUrl($href) + && ($mediaValue === 'all' || $mediaValue === 'screen') + ) { + $usedUrls[] = $href; + return $this->anchor(self::CSS_ANCHOR, $anchored); + } + + if ($local && $this->mapHas($css['inline'] ?? [], $key)) { + // Inlining moves the rules into the document, so relative url() + // and @import must be resolved against the original stylesheet + // or every referenced font and image 404s. + $content = $this->minifier->cssForCombine($href); + if ($content !== '') { + return ''; + } + } + + $deferThis = ! empty($css['defer']) && ! $this->fileExcluded($css, $href); + + if ($local && $this->mapHas($css['combine'] ?? [], $key) && (empty($css['defer']) || $deferThis)) { + $combine[$mediaValue][] = $href; + return $this->anchor(self::CSS_ANCHOR, $anchored); + } + + if ($local && $this->mapHas($css['minify'] ?? [], $key)) { + $href = $this->minifier->file($href, 'css'); + } + if (! empty($cdn['enabled']) && $local) { + $href = $this->cdnRewrite($href, $cdn); + } + $attrs['href'] = $href; + + if ($deferThis) { + // The noscript copy is what styles the page when the onload swap + // never runs. Its id is dropped so the two never collide. + $fallback = $attrs; + unset($fallback['id']); + + // A preload whose media query does not match is never fetched, so + // its onload never fires: the media moves onto the handler. + unset($attrs['media']); + $attrs['rel'] = 'preload'; + $attrs['as'] = 'style'; + $attrs['onload'] = 'this.onload=null;' . $this->onloadMedia($mediaValue) . "this.rel='stylesheet'"; + + return $this->buildVoidTag('link', $attrs) + . ''; + } + + return $this->buildVoidTag('link', $attrs); + }, $html); + + return $result ?? $html; + } + + private function minifyInlineStyles(string $html): string + { + $result = preg_replace_callback('#]*)>(.*?)#is', function (array $m): string { + if (trim($m[2]) === '') { + return $m[0]; + } + return '' . $this->minifier->cssCode($m[2]) . ''; + }, $html); + + return $result ?? $html; + } + + /** + * @param array $js + * @param array $cdn + * @param string[] $combine + */ + private function processJs(string $html, array $js, array $cdn, array &$combine, bool &$delayed): string + { + $delay = ! empty($js['delay']); + $anchored = false; + + $result = preg_replace_callback('#])*)>(.*?)#is', function (array $m) use ($js, $cdn, &$combine, &$delayed, &$anchored, $delay): string { + $attrs = $this->parseAttrs(''); + $content = $m[2]; + $type = strtolower((string) ($attrs['type'] ?? '')); + + // Allow-list, not a deny-list: anything that is not executable + // JavaScript (JSON-LD, import maps, speculation rules, template and + // data blocks) must be passed through byte for byte. + if (! $this->isJavaScriptType($type)) { + return $m[0]; + } + + $src = (string) ($attrs['src'] ?? ''); + + if ($src === '') { + $code = (! empty($js['minify_inline']) && trim($content) !== '') + ? $this->minifier->jsCode($content) + : $content; + + if ($delay && $type !== 'module' && trim($code) !== '' && ! $this->delayExcluded($js, $code)) { + $attrs['type'] = 'wpp/lazy'; + $delayed = true; + return $this->scriptTag($attrs, $code); + } + return $code !== $content ? $this->scriptTag($attrs, $code) : $m[0]; + } + + if (str_contains($src, '/wpp-cache/')) { + return $m[0]; + } + + $local = Assets::isLocal($src); + $key = $this->key($src); + $this->collection->record('js', $this->group($src, $local), $key); + + if ($this->isDisabled($js, $key)) { + return ''; + } + + if ($local && $this->mapHas($js['inline'] ?? [], $key)) { + $code = Assets::contents($src); + if ($code !== null) { + if ($this->mapHas($js['minify'] ?? [], $key)) { + $code = $this->minifier->jsCode($code); + } + unset($attrs['src']); + if ($delay && $type !== 'module' && ! $this->delayExcluded($js, $src)) { + $attrs['type'] = 'wpp/lazy'; + $delayed = true; + } + return $this->scriptTag($attrs, $code); + } + } + + $deferThis = ! empty($js['defer']) && $type !== 'module' && ! $this->fileExcluded($js, $src); + + // A script the user excluded from delay must not be swept into the + // combined bundle, which is itself delayed as a whole. + $delayExcluded = $delay && $this->delayExcluded($js, $src); + + if ($local && ! $delayExcluded + && $this->mapHas($js['combine'] ?? [], $key) + && (empty($js['defer']) || $deferThis) + ) { + $combine[] = $src; + // The bundle replaces the first combined tag: emitting it before + // would run it after inline code that depends on it. + return $this->anchor(self::JS_ANCHOR, $anchored); + } + + if ($local && $this->mapHas($js['minify'] ?? [], $key)) { + $src = $this->minifier->file($src, 'js'); + } + if (! empty($cdn['enabled']) && $local) { + $src = $this->cdnRewrite($src, $cdn); + } + + if ($delay && $type !== 'module' && ! $this->delayExcluded($js, $src)) { + unset($attrs['src']); + $attrs['type'] = 'wpp/lazy'; + $attrs['data-wpp-src'] = $src; + $delayed = true; + return $this->scriptTag($attrs, ''); + } + + $attrs['src'] = $src; + if ($deferThis) { + $attrs['defer'] = true; + } + + return $this->scriptTag($attrs, ''); + }, $html); + + return $result ?? $html; + } + + /** @param array $js whether a script src/inline-code is excluded from delay */ + private function delayExcluded(array $js, string $needle): bool + { + foreach ((array) ($js['delay_exclude'] ?? []) as $pattern) { + if ($pattern !== '' && str_contains($needle, (string) $pattern)) { + return true; + } + } + return false; + } + + private function loaderScript(): string + { + return ''; + } + + /** + * @param array $media + * @param array $cdn + * @param array $preloads collected LCP images + */ + private function processImages(string $html, array $media, array $cdn, array &$preloads): string + { + // The page-URL control, matching the video one: the by-name/by-src + // control is images_exclude. + if (Url::anyMatch((array) ($media['images_exclude_urls'] ?? []), $this->currentUrl)) { + return $html; + } + + $disableOnMobile = ! empty($media['images_lazy_disable_mobile']) && wp_is_mobile(); + $lazy = ! empty($media['images_lazy']) && ! $disableOnMobile; + $cdnOn = ! empty($cdn['enabled']); + $responsive = ! empty($media['images_responsive']); + $dimensions = ! empty($media['images_dimensions']); + $lcp = max(0, (int) ($media['lcp_images'] ?? 0)); + $nextgen = ! empty($media['webp']); + + if (! $lazy && ! $cdnOn && ! $responsive && ! $dimensions && ! $nextgen && $lcp === 0) { + return $html; + } + + $containers = array_filter((array) ($media['images_exclude_containers'] ?? [])); + if ($containers !== []) { + $html = $this->markContainers($html, $containers); + } + if ($nextgen) { + $html = $this->markPictureImages($html); + } + + $index = 0; + $result = preg_replace_callback('#])*>#i', function (array $m) use ($media, $cdn, $lazy, $cdnOn, $responsive, $dimensions, $lcp, $nextgen, &$preloads, &$index): string { + $inPicture = str_contains($m[0], 'data-wpp-picture="1"'); + if ($inPicture) { + $m[0] = str_replace(' data-wpp-picture="1"', '', $m[0]); + } + + if (str_contains($m[0], 'data-wpp-skip')) { + return str_replace(' data-wpp-skip="1"', '', $m[0]); + } + + $attrs = $this->parseAttrs($m[0]); + $src = (string) ($attrs['src'] ?? ''); + if ($src === '' || $this->imgExcluded($attrs, $src, $media)) { + return $m[0]; + } + + $isLcp = $lcp > 0 && $index < $lcp; + $index++; + $changed = false; + + if ($dimensions && (empty($attrs['width']) || empty($attrs['height']))) { + [$w, $h] = $this->imageDimensions($src); + if ($w !== null && $h !== null) { + if (empty($attrs['width'])) { + $attrs['width'] = $w; + } + if (empty($attrs['height'])) { + $attrs['height'] = $h; + } + $changed = true; + } + } + + if ($responsive && (string) ($attrs['srcset'] ?? '') === '' && Assets::isLocal($src) + && function_exists('attachment_url_to_postid') + ) { + $id = attachment_url_to_postid(Assets::stripQuery($src)); + if ($id) { + $srcset = wp_get_attachment_image_srcset($id, 'full'); + if ($srcset) { + $attrs['srcset'] = $srcset; + $sizes = wp_get_attachment_image_sizes($id, 'full'); + if ($sizes) { + $attrs['sizes'] = $sizes; + } + $changed = true; + } + } + } + + // Next-gen siblings are probed on disk, which only the origin URLs + // can resolve to. + $originSrc = $src; + $originSrcset = (string) ($attrs['srcset'] ?? ''); + + if ($cdnOn && Assets::isLocal($src)) { + $attrs['src'] = $this->cdnRewrite($src, $cdn); + $changed = true; + } + + // Responsive images serve from srcset, so leaving it alone means + // most images bypass the CDN entirely. + if ($cdnOn && ! empty($attrs['srcset']) && is_string($attrs['srcset'])) { + $rewritten = $this->cdnRewriteSrcset((string) $attrs['srcset'], $cdn); + if ($rewritten !== $attrs['srcset']) { + $attrs['srcset'] = $rewritten; + $changed = true; + } + } + + if ($isLcp) { + $attrs['loading'] = 'eager'; + if (empty($attrs['fetchpriority'])) { + $attrs['fetchpriority'] = 'high'; + } + $changed = true; + } elseif ($lazy) { + if (empty($attrs['loading'])) { + $attrs['loading'] = 'lazy'; + $changed = true; + } + if (empty($attrs['decoding'])) { + $attrs['decoding'] = 'async'; + $changed = true; + } + } + + $imgTag = $changed ? $this->buildVoidTag('img', $attrs) : $m[0]; + + // An that already sits in a only ever sees that + // picture's own s, so wrapping it again disables them. + $sources = $nextgen && ! $inPicture + ? $this->nextgenSources($originSrc, $originSrcset, (string) ($attrs['sizes'] ?? ''), $cdnOn ? $cdn : null) + : []; + + if ($isLcp) { + $preloads[] = $this->preloadFor($sources, $attrs, $src); + } + + return $sources === [] ? $imgTag : $this->wrapPicture($imgTag, $sources); + }, $html); + + return $result ?? $html; + } + + /** + * Mark every that already lives inside a . + */ + private function markPictureImages(string $html): string + { + if (stripos($html, '])*>.*?#is', + static fn (array $m): string => (string) preg_replace('# $sources + */ + private function wrapPicture(string $imgTag, array $sources): string + { + $tags = ''; + foreach ($sources as $source) { + $tags .= ''; + } + + return '' . $tags . $imgTag . ''; + } + + /** + * The avif/webp s whose sibling files all exist, best format first. + * + * @param array|null $cdn + * @return list + */ + private function nextgenSources(string $src, string $srcset, string $sizes, ?array $cdn): array + { + $sources = []; + foreach (['avif' => 'image/avif', 'webp' => 'image/webp'] as $format => $mime) { + $nextgen = $this->nextgenSrcset($src, $srcset, $format, $cdn); + if ($nextgen === '') { + continue; + } + $sources[] = [ + 'srcset' => $nextgen, + // A without sizes defaults to a source size of 100vw, + // so width descriptors would resolve to a larger candidate than + // the itself picks. + 'sizes' => $this->hasWidthDescriptor($nextgen) ? $sizes : '', + 'type' => $mime, + ]; + } + + return $sources; + } + + /** + * Build a next-gen srcset from the origin src/srcset. Empty unless every + * candidate has a sibling: a partial set would let the browser pick a small + * next-gen file for a slot the original srcset covered. + * + * @param array|null $cdn + */ + private function nextgenSrcset(string $src, string $srcset, string $format, ?array $cdn): string + { + $entries = []; + + if ($srcset !== '') { + foreach (explode(',', $srcset) as $candidate) { + $candidate = trim($candidate); + if ($candidate === '') { + continue; + } + $parts = preg_split('/\s+/', $candidate, 2); + $url = $parts[0]; + $descriptor = isset($parts[1]) ? ' ' . $parts[1] : ''; + if (! $this->nextgenExists($url, $format)) { + return ''; + } + $entries[] = $this->nextgenUrl($url, $format, $cdn) . $descriptor; + } + } elseif ($src !== '' && $this->nextgenExists($src, $format)) { + $entries[] = $this->nextgenUrl($src, $format, $cdn); + } + + return implode(', ', $entries); + } + + private function hasWidthDescriptor(string $srcset): bool + { + return (bool) preg_match('/\s\d+w\s*(?:,|$)/', $srcset); + } + + /** + * The LCP preload for one image: whatever the browser will actually decode, + * which is the first when a was emitted. + * + * @param list $sources + * @param array $attrs + * @return array{src:string,srcset:string,sizes:string,type:string} + */ + private function preloadFor(array $sources, array $attrs, string $src): array + { + if ($sources === []) { + return [ + 'src' => (string) ($attrs['src'] ?? $src), + 'srcset' => (string) ($attrs['srcset'] ?? ''), + 'sizes' => (string) ($attrs['sizes'] ?? ''), + 'type' => '', + ]; + } + + $first = $sources[0]; + $lead = $this->firstCandidate($first['srcset']); + + return [ + 'src' => $lead, + 'srcset' => $lead === $first['srcset'] ? '' : $first['srcset'], + 'sizes' => $first['sizes'], + 'type' => $first['type'], + ]; + } + + /** The URL of a srcset's first candidate, without its descriptor. */ + private function firstCandidate(string $srcset): string + { + $parts = preg_split('/\s+/', trim(explode(',', $srcset, 2)[0]), 2) ?: []; + + return (string) ($parts[0] ?? ''); + } + + /** @param array|null $cdn */ + private function nextgenUrl(string $url, string $format, ?array $cdn): string + { + $pos = strpos($url, '?'); + $query = $pos === false ? '' : substr($url, $pos); + $base = ($pos === false ? $url : substr($url, 0, $pos)) . '.' . $format; + + return ($cdn !== null && Assets::isLocal($base) ? $this->cdnRewrite($base, $cdn) : $base) . $query; + } + + /** + * Existence probe for an image's next-gen sibling. Images are outside + * Assets::toPath()'s readable set, so the path is resolved here; it is only + * ever passed to is_file(), never read. + */ + private function nextgenExists(string $url, string $format): bool + { + $url = Assets::stripQuery(Assets::normalize($url)); + $contentUrl = content_url(); + $home = home_url(); + + if (str_starts_with($url, $contentUrl)) { + $path = WP_CONTENT_DIR . '/' . ltrim(substr($url, strlen($contentUrl)), '/'); + } elseif (str_starts_with($url, $home)) { + $path = ABSPATH . ltrim(substr($url, strlen($home)), '/'); + } elseif (str_starts_with($url, '/') && ! str_starts_with($url, '//')) { + $path = ABSPATH . ltrim($url, '/'); + } else { + return false; + } + + $real = realpath($path . '.' . $format); + // A zero-byte file is a half-finished conversion: advertising it in a + // would serve a broken image in place of a working one. + if ($real === false || ! is_file($real) || filesize($real) === 0) { + return false; + } + + foreach ([ABSPATH, WP_CONTENT_DIR] as $root) { + $resolved = realpath($root); + if ($resolved !== false && str_starts_with($real, rtrim($resolved, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR)) { + return true; + } + } + + return false; + } + + /** @return array{0:?string,1:?string} width/height from a sized filename or attachment metadata */ + private function imageDimensions(string $src): array + { + if (preg_match('/-(\d+)x(\d+)\.[a-z0-9]+(?:\?.*)?$/i', $src, $m)) { + return [$m[1], $m[2]]; + } + if (Assets::isLocal($src) && function_exists('attachment_url_to_postid')) { + $id = attachment_url_to_postid(Assets::stripQuery($src)); + if ($id) { + $meta = wp_get_attachment_metadata($id); + if (! empty($meta['width']) && ! empty($meta['height'])) { + return [(string) $meta['width'], (string) $meta['height']]; + } + } + } + return [null, null]; + } + + /** + * Add a data-wpp-skip marker to tags inside elements matching the + * given CSS-ish selectors (#id, .class, or a bare id/class name). + * + * @param string[] $selectors + */ + private function markContainers(string $html, array $selectors): string + { + foreach ($selectors as $selector) { + $selector = trim((string) $selector); + if ($selector === '') { + continue; + } + + if (str_starts_with($selector, '#')) { + $attr = 'id'; + $name = substr($selector, 1); + } elseif (str_starts_with($selector, '.')) { + $attr = 'class'; + $name = substr($selector, 1); + } else { + $attr = 'id|class'; + $name = $selector; + } + $name = preg_quote($name, '#'); + + $pattern = '#<([a-zA-Z0-9]+)\b[^>]*\b(?:' . $attr . ')\s*=\s*["\'][^"\']*\b' . $name . '\b[^"\']*["\'][^>]*>#i'; + if (! preg_match_all($pattern, $html, $matches, PREG_OFFSET_CAPTURE)) { + continue; + } + + $ranges = []; + foreach ($matches[0] as $i => $match) { + $tag = strtolower($matches[1][$i][0]); + $openEnd = (int) $match[1] + strlen($match[0]); + $ranges[] = [$openEnd, $this->matchingClose($html, $tag, $openEnd)]; + } + + usort($ranges, static fn (array $a, array $b): int => $b[0] <=> $a[0]); + foreach ($ranges as [$start, $end]) { + $segment = substr($html, $start, $end - $start); + $marked = (string) preg_replace('#]*>#i', $html, $matches, PREG_OFFSET_CAPTURE, $from)) { + return $length; + } + + $depth = 1; + foreach ($matches[0] as $i => $match) { + if ($matches[1][$i][0] === '/') { + $depth--; + if ($depth === 0) { + return (int) $match[1] + strlen($match[0]); + } + } else { + $depth++; + } + } + + return $length; + } + + /** @param array $media */ + private function processIframes(string $html, array $media): string + { + if (empty($media['videos_lazy'])) { + return $html; + } + + $excludes = (array) ($media['videos_exclude_urls'] ?? []); + if (Url::anyMatch($excludes, $this->currentUrl)) { + return $html; + } + + $result = preg_replace_callback('#])*>#i', function (array $m) use ($excludes): string { + $attrs = $this->parseAttrs($m[0]); + if (! empty($attrs['loading'])) { + return $m[0]; + } + if (Url::anyMatch($excludes, (string) ($attrs['src'] ?? ''))) { + return $m[0]; + } + $attrs['loading'] = 'lazy'; + return $this->buildVoidTag('iframe', $attrs); + }, $html); + + return $result ?? $html; + } + + /** @param array $media */ + private function imgExcluded(array $attrs, string $src, array $media): bool + { + foreach ((array) ($media['images_exclude'] ?? []) as $name) { + if ($name !== '' && str_contains($src, (string) $name)) { + return true; + } + } + return false; + } + + /** @param array $cfg */ + private function isDisabled(array $cfg, string $key): bool + { + if (empty($cfg['disable'][$key])) { + return false; + } + $position = $cfg['disable_position'][$key] ?? 'everywhere'; + + if ($position === 'selected') { + return Url::anyMatch((array) ($cfg['disable_selected'][$key] ?? []), $this->currentUrl); + } + if ($position === 'except') { + return ! Url::anyMatch((array) ($cfg['disable_except'][$key] ?? []), $this->currentUrl); + } + return true; + } + + /** + * @param string[] $urls + * @param array $cdn + */ + private function combine(array $urls, string $type, array $cdn): ?string + { + $hash = md5($this->sourceKey($urls)); + $file = WPP_CACHE_DIR . $hash . '.' . $type; + $url = WPP_CACHE_URL . $hash . '.' . $type; + + // The cache key is the source list, so an artifact written from a failed + // read would be re-served for as long as the sources keep their mtime. + if (is_file($file) && filesize($file) === 0) { + @unlink($file); + } + + if (! is_file($file)) { + $buffer = $this->combineSources($urls, $type); + if ($buffer === null || ! $this->writeAtomic($file, $buffer)) { + return null; + } + } + + return ! empty($cdn['enabled']) ? $this->cdnRewrite($url, $cdn) : $url; + } + + /** + * Concatenate the sources, or null when any of them could not be read. + * + * @param string[] $urls + */ + private function combineSources(array $urls, string $type): ?string + { + $buffer = ''; + foreach ($urls as $assetUrl) { + $piece = $this->fetchForCombine($assetUrl, $type); + if ($this->fetchFailed($piece, $assetUrl)) { + return null; + } + $buffer .= $piece . "\n"; + } + + return $type === 'css' ? CssMinifier::hoistAtRules($buffer) : $buffer; + } + + /** An empty result is a failed read unless the source file is itself empty. */ + private function fetchFailed(string $piece, string $url): bool + { + if (trim($piece, " \t\r\n;") !== '') { + return false; + } + $path = Assets::toPath($url); + + return $path === null || (int) @filesize($path) > 0; + } + + /** Write through a temp file so a partial write is never published. */ + private function writeAtomic(string $file, string $contents): bool + { + $dir = dirname($file); + if (! is_dir($dir) && ! wp_mkdir_p($dir)) { + return false; + } + + $tmp = $file . '.' . getmypid() . '.tmp'; + if (file_put_contents($tmp, $contents, LOCK_EX) !== strlen($contents) || ! rename($tmp, $file)) { + @unlink($tmp); + return false; + } + + return true; + } + + /** + * Cache identity of a source list: edits to a file must produce a new key + * even when its URL never changes. + * + * @param string[] $urls + */ + private function sourceKey(array $urls): string + { + $parts = []; + foreach ($urls as $url) { + $path = Assets::toPath((string) $url); + $parts[] = $url . ':' . ($path === null ? '' : (string) @filemtime($path)); + } + + return implode('|', $parts); + } + + private function fetchForCombine(string $assetUrl, string $type): string + { + return $type === 'css' + ? $this->minifier->cssForCombine($assetUrl) + : $this->minifier->jsForCombine($assetUrl); + } + + /** + * Build (and cache per URL) the used-CSS for the current page. + * + * @param string[] $urls + * @param array $css + */ + private function buildUsedCss(array $urls, string $html, array $css): string + { + $safelist = (array) ($css['used_safelist'] ?? []); + + // Keyed on the queried object rather than the raw URL. Keying on the URL + // let anyone mint unlimited cache entries with junk query strings and + // fill the disk. + $hash = md5($this->usedCssScope() . '|' . $this->sourceKey($urls) . '|' . implode('|', $safelist)); + $file = WPP_CACHE_DIR . 'used/' . $hash . '.css'; + + if (is_file($file)) { + return (string) file_get_contents($file); + } + if (! is_dir(WPP_CACHE_DIR . 'used/') && ! wp_mkdir_p(WPP_CACHE_DIR . 'used/')) { + return ''; + } + + $used = CssMinifier::hoistAtRules((new UsedCss())->build($html, $urls, $safelist)); + file_put_contents($file, $used, LOCK_EX); + + return $used; + } + + /** @param array $cdn */ + /** @param array $cdn Rewrite each candidate, keeping its descriptor. */ + private function cdnRewriteSrcset(string $srcset, array $cdn): string + { + $out = []; + foreach (explode(',', $srcset) as $candidate) { + $candidate = trim($candidate); + if ($candidate === '') { + continue; + } + $parts = preg_split('/\s+/', $candidate, 2); + $url = $parts[0]; + $desc = isset($parts[1]) ? ' ' . $parts[1] : ''; + $out[] = (Assets::isLocal($url) ? $this->cdnRewrite($url, $cdn) : $url) . $desc; + } + + return implode(', ', $out); + } + + private function cdnRewrite(string $url, array $cdn): string + { + $hostname = rtrim(trim((string) ($cdn['hostname'] ?? '')), '/'); + + // Without a scheme the prefix is a document-relative path, which would + // 404 every asset on the site. + if ($hostname === '' + || (! str_starts_with($hostname, '//') && parse_url($hostname, PHP_URL_SCHEME) === null) + ) { + return $url; + } + + if (Url::anyMatch((array) ($cdn['exclude'] ?? []), $url)) { + return $url; + } + + if (str_starts_with($url, '/') && ! str_starts_with($url, '//')) { + return $hostname . $url; + } + + $path = $this->originPath($url); + + return $path === null ? $url : $hostname . $path; + } + + /** Path of a URL served by this site, ignoring the scheme, or null. */ + private function originPath(string $url): ?string + { + $strip = static fn (string $u): string => (string) preg_replace('#^https?://#i', '', $u); + $bare = $strip(Assets::normalize($url)); + $origin = $strip(home_url()); + + if ($origin === '' || ! str_starts_with($bare, $origin)) { + return null; + } + + $path = substr($bare, strlen($origin)); + + if ($path === '') { + return '/'; + } + + return str_starts_with($path, '/') ? $path : null; + } + + private function anchor(string $marker, bool &$anchored): string + { + if ($anchored) { + return ''; + } + $anchored = true; + + return $marker; + } + + /** Put $insert where the anchor stands, or before $fallback when there is none. */ + private function placeAnchored(string $html, string $marker, string $insert, string $fallback): string + { + if (str_contains($html, $marker)) { + return str_replace($marker, $insert, $html); + } + + return $insert === '' ? $html : $this->injectBefore($html, $fallback, $insert); + } + + /** @param array{src:string,srcset:string,sizes:string,type:string} $preload */ + private function imagePreloadTag(array $preload): string + { + $tag = ' source it will select and skip a format it cannot decode. + if ($preload['type'] !== '') { + $tag .= ' type="' . esc_attr($preload['type']) . '"'; + } + + // Without the candidate list the browser preloads the src and then + // downloads a different candidate for the element itself. + if ($preload['srcset'] !== '') { + $tag .= ' imagesrcset="' . esc_attr($preload['srcset']) . '"'; + } + if ($preload['sizes'] !== '') { + $tag .= ' imagesizes="' . esc_attr($preload['sizes']) . '"'; + } + + return $tag . '>'; + } + + /** Assignment restoring a stylesheet's media once a preload has loaded. */ + private function onloadMedia(string $media): string + { + $media = str_replace(['\\', "'"], '', $media); + + return $media === '' || $media === 'all' ? '' : "this.media='" . $media . "';"; + } + + private function injectBefore(string $html, string $needle, string $insert): string + { + $pos = stripos($html, $needle); + if ($pos === false) { + return $html . $insert; + } + return substr($html, 0, $pos) . $insert . substr($html, $pos); + } + + private function group(string $url, bool $local): string + { + if (! $local) { + return 'external'; + } + $path = (string) Assets::toPath($url); + if (str_contains($path, '/plugins/') || str_contains($path, '/mu-plugins/')) { + return 'plugin'; + } + return 'theme'; + } + + private function key(string $url): string + { + return Assets::stripQuery(Assets::normalize($url)); + } + + /** @param array $map */ + /** A bounded identifier for the page being rendered. */ + private function usedCssScope(): string + { + if (function_exists('is_singular') && is_singular()) { + $id = get_queried_object_id(); + if ($id) { + return 'post-' . $id; + } + } + + if (function_exists('is_front_page') && is_front_page()) { + return 'front'; + } + + $template = $GLOBALS['template'] ?? ''; + return is_string($template) && $template !== '' ? 'tpl-' . basename($template) : 'generic'; + } + + /** True only for script types the browser executes as JavaScript. */ + private function isJavaScriptType(string $type): bool + { + return in_array($type, [ + '', + 'text/javascript', + 'application/javascript', + 'application/ecmascript', + 'text/ecmascript', + 'module', + ], true); + } + + private function isStylesheetUrl(string $url): bool + { + $path = (string) parse_url(Assets::stripQuery($url), PHP_URL_PATH); + return strtolower(pathinfo($path, PATHINFO_EXTENSION)) === 'css'; + } + + private function mapHas(array $map, string $key): bool + { + return ! empty($map[$key]); + } + + /** @param array $cfg whether a URL is in the "exclude from async" list */ + private function fileExcluded(array $cfg, string $url): bool + { + foreach ((array) ($cfg['file_exclude'] ?? []) as $pattern) { + if ($pattern !== '' && (str_contains($url, (string) $pattern) || Url::matches((string) $pattern, $url))) { + return true; + } + } + return false; + } + + /** + * Handle a Google Fonts stylesheet link: collect for combination, or apply + * font-display + async in place. + * + * @param array $attrs + * @param array $css + * @param array $googleFonts + */ + private function googleFontLink(string $href, array $attrs, array $css, array &$googleFonts, bool &$anchored): string + { + parse_str((string) parse_url($href, PHP_URL_QUERY), $query); + + // parse_str keeps only the last value, and the css2 endpoint repeats + // family= once per family. + $families = $this->queryValues((string) parse_url($href, PHP_URL_QUERY), 'family'); + $endpoint = str_contains((string) parse_url($href, PHP_URL_PATH), '/css2') ? 'css2' : 'css'; + + if (! empty($css['combine_fonts']) || ! empty($css['host_fonts'])) { + if ($families !== []) { + foreach ($families as $family) { + $googleFonts[$endpoint][] = $family; + } + return $this->anchor(self::CSS_ANCHOR, $anchored); + } + } + + $display = (string) ($css['font_display'] ?? 'none'); + if ($display !== 'none' && $display !== '' && ! isset($query['display'])) { + $href .= (parse_url($href, PHP_URL_QUERY) ? '&' : '?') . 'display=' . $display; + $attrs['href'] = $href; + } + + if (! empty($css['defer']) && ! $this->fileExcluded($css, $href)) { + $attrs['rel'] = 'preload'; + $attrs['as'] = 'style'; + $attrs['onload'] = "this.onload=null;this.rel='stylesheet'"; + } + + return $this->buildVoidTag('link', $attrs); + } + + private function styleTag(string $url, bool $defer, string $media = 'all'): string + { + $attr = $media === '' || $media === 'all' ? '' : ' media="' . esc_attr($media) . '"'; + $plain = ''; + + if ($defer) { + // The noscript copy is what styles the page when the onload swap + // never runs, which is otherwise a completely unstyled document. + return '' + . ''; + } + + return $plain; + } + + /** + * @param string[] $families raw, still-encoded family values + * @param array $css + */ + private function googleFontsUrl(string $endpoint, array $families, array $css): string + { + $families = array_values(array_unique($families)); + + $url = $endpoint === 'css2' + ? 'https://fonts.googleapis.com/css2?family=' . implode('&family=', $families) + : 'https://fonts.googleapis.com/css?family=' . implode('|', $families); + + $display = (string) ($css['font_display'] ?? 'none'); + if (in_array($display, ['auto', 'block', 'swap', 'fallback', 'optional'], true)) { + $url .= '&display=' . $display; + } + + return $url; + } + + /** + * Values of a repeated query parameter, left encoded as the source had them. + * + * @return string[] + */ + private function queryValues(string $query, string $name): array + { + $out = []; + foreach (explode('&', $query) as $pair) { + if ($pair === '') { + continue; + } + [$key, $value] = array_pad(explode('=', $pair, 2), 2, ''); + if (rawurldecode($key) === $name && $value !== '') { + $out[] = $value; + } + } + + return $out; + } + + /** + * Parse a single tag's attributes into a map. Boolean attributes => true. + * + * @return array + */ + private function parseAttrs(string $tag): array + { + $inner = (string) preg_replace('#^<\s*[a-zA-Z0-9]+#', '', trim($tag)); + $inner = (string) preg_replace('#/?>$#', '', $inner); + + $attrs = []; + preg_match_all( + '#([a-zA-Z0-9:_.\-]+)\s*(=\s*("([^"]*)"|\'([^\']*)\'|([^\s"\'=>]+)))?#', + $inner, + $matches, + PREG_SET_ORDER + ); + + foreach ($matches as $m) { + $name = strtolower($m[1]); + if ($name === '') { + continue; + } + if (! isset($m[2]) || $m[2] === '') { + $attrs[$name] = true; + continue; + } + $value = $m[4] ?? ''; + if ($value === '' && ($m[5] ?? '') !== '') { + $value = $m[5]; + } + if ($value === '' && ($m[6] ?? '') !== '') { + $value = $m[6]; + } + $attrs[$name] = html_entity_decode($value, ENT_QUOTES); + } + + return $attrs; + } + + /** @param array $attrs */ + private function buildVoidTag(string $name, array $attrs): string + { + return '<' . $name . $this->renderAttrs($attrs) . '>'; + } + + /** @param array $attrs */ + private function scriptTag(array $attrs, string $content): string + { + return 'renderAttrs($attrs) . '>' . $content . ''; + } + + /** @param array $attrs */ + private function renderAttrs(array $attrs): string + { + $out = ''; + foreach ($attrs as $name => $value) { + if ($value === true) { + $out .= ' ' . $name; + } elseif ($value === false || $value === null) { + continue; + } else { + $out .= ' ' . $name . '="' . esc_attr((string) $value) . '"'; + } + } + return $out; + } +} diff --git a/src/Optimize/Collection.php b/src/Optimize/Collection.php new file mode 100644 index 0000000..d461332 --- /dev/null +++ b/src/Optimize/Collection.php @@ -0,0 +1,79 @@ +> type => group => urls */ + private array $buffer = []; + + public function record(string $type, string $group, string $url): void + { + $this->buffer[$type][$group][] = $url; + } + + public function flush(): void + { + if ($this->buffer === []) { + return; + } + + $stored = $this->all(); + $changed = false; + + foreach ($this->buffer as $type => $groups) { + foreach ($groups as $group => $urls) { + $existing = $stored[$type][$group] ?? []; + $merged = array_values(array_unique(array_merge($existing, $urls))); + if ($merged !== $existing) { + $stored[$type][$group] = $merged; + $changed = true; + } + } + } + + if ($changed) { + update_option(self::OPTION, $stored, false); + } + + $this->buffer = []; + } + + /** @return array> */ + public function all(): array + { + $value = get_option(self::OPTION, []); + return is_array($value) ? $value : []; + } + + public function clear(): void + { + delete_option(self::OPTION); + } + + /** + * Drop the cached option so a value written by another process becomes + * visible. delete_option() adds the key to the 'notoptions' cache, so after + * a rescan clears the list the same request would otherwise keep reading the + * default and never see what the loopback request just collected. + */ + public function refresh(): void + { + wp_cache_delete(self::OPTION, 'options'); + + $notoptions = wp_cache_get('notoptions', 'options'); + if (is_array($notoptions) && isset($notoptions[self::OPTION])) { + unset($notoptions[self::OPTION]); + wp_cache_set('notoptions', $notoptions, 'options'); + } + } +} diff --git a/src/Optimize/CssMinifier.php b/src/Optimize/CssMinifier.php new file mode 100644 index 0000000..f2281c1 --- /dev/null +++ b/src/Optimize/CssMinifier.php @@ -0,0 +1,219 @@ +])\s*/', '$1', $css); // around structural chars + // Collapse colon spacing only when whitespace follows (declarations like + // "color: red"); selectors like ".x :hover" have no space after the colon. + $css = (string) preg_replace('/\s*:\s+/', ':', $css); + $css = str_replace(';}', '}', $css); // trailing semicolons + $css = trim($css); + + return strtr($css, $strings); + } + + public function process(string $css, string $sourceUrl): string + { + return $this->minify($this->absolutize($css, $sourceUrl)); + } + + /** + * Move @charset and top-level @import to the front of a stylesheet. An + * @import preceded by any other rule is invalid and the browser drops it, + * which is what concatenating stylesheets produces on its own. + */ + public static function hoistAtRules(string $css): string + { + if (stripos($css, '@import') === false && stripos($css, '@charset') === false) { + return $css; + } + + $charset = ''; + $imports = ''; + $rest = ''; + + foreach (self::topLevelStatements($css) as $statement) { + $head = ltrim($statement); + if (preg_match('/^@import\b/i', $head)) { + $imports .= $head; + } elseif (preg_match('/^@charset\b/i', $head)) { + // Only the first @charset is ever honored. + if ($charset === '') { + $charset = $head; + } + } else { + $rest .= $statement; + } + } + + return $charset . $imports . $rest; + } + + /** + * Split CSS into top-level statements, brace- and quote-aware. + * + * @return string[] + */ + private static function topLevelStatements(string $css): array + { + $statements = []; + $length = strlen($css); + $depth = 0; + $start = 0; + $quote = ''; + + for ($i = 0; $i < $length; $i++) { + $char = $css[$i]; + + if ($quote !== '') { + if ($char === '\\') { + $i++; + } elseif ($char === $quote) { + $quote = ''; + } + continue; + } + + if ($char === '"' || $char === '\'') { + $quote = $char; + } elseif ($char === '{') { + $depth++; + } elseif ($char === '}') { + $depth--; + if ($depth <= 0) { + $statements[] = substr($css, $start, $i - $start + 1); + $start = $i + 1; + $depth = 0; + } + } elseif ($char === ';' && $depth === 0) { + $statements[] = substr($css, $start, $i - $start + 1); + $start = $i + 1; + } + } + + $tail = substr($css, $start); + if (trim($tail) !== '') { + $statements[] = $tail; + } + + return $statements; + } + + private function absolutize(string $css, string $sourceUrl): string + { + // Quotes are re-emitted: an unquoted url() token may not contain + // whitespace, quotes or parentheses. + $count = 0; + $css = (string) preg_replace_callback( + '/url\(\s*(?:"([^"]*)"|\'([^\']*)\'|([^"\'()\s]*))\s*\)/i', + function (array $m) use ($sourceUrl): string { + $quote = $m[1] !== null ? '"' : ($m[2] !== null ? '\'' : ''); + $value = $m[1] ?? $m[2] ?? $m[3] ?? ''; + return 'url(' . $quote . $this->resolve($sourceUrl, trim($value)) . $quote . ')'; + }, + $css, + -1, + $count, + PREG_UNMATCHED_AS_NULL + ); + + return (string) preg_replace_callback( + '/@import\s+(["\'])([^"\']+)\1/i', + fn (array $m): string => '@import "' . $this->resolve($sourceUrl, $m[2]) . '"', + $css + ); + } + + private function resolve(string $sourceUrl, string $rel): string + { + // Anything already absolute, a data/blob payload, or a bare fragment is + // returned untouched. The delimiter must not be '#', which would end the + // pattern at the fragment alternative and silently match nothing. + if ($rel === '' || preg_match('~^(?:[a-z][a-z0-9+.-]*:|//|#)~i', $rel)) { + return $rel; + } + + $source = Assets::normalize($sourceUrl); + $scheme = (string) parse_url($source, PHP_URL_SCHEME); + $host = (string) parse_url($source, PHP_URL_HOST); + $port = parse_url($source, PHP_URL_PORT); + + // A root-relative stylesheet href carries no origin of its own, and an + // empty authority ("http:///path") is parsed by browsers as the host + // being the first path segment, so every reference would 404. + if ($host === '') { + $home = home_url(); + $scheme = (string) parse_url($home, PHP_URL_SCHEME); + $host = (string) parse_url($home, PHP_URL_HOST); + $port = parse_url($home, PHP_URL_PORT); + } + if ($host === '') { + return $rel; + } + + $origin = ($scheme === '' ? 'http' : $scheme) . '://' . $host . ($port !== null ? ':' . $port : ''); + $srcPath = (string) parse_url($source, PHP_URL_PATH); + if ($srcPath === '' || $srcPath[0] !== '/') { + $srcPath = '/' . $srcPath; + } + + if (str_starts_with($rel, '/')) { + $path = $rel; + } else { + $dir = substr($srcPath, 0, (int) strrpos($srcPath, '/') + 1); + $path = $dir . $rel; + } + + return $origin . $this->normalizePath($path); + } + + private function normalizePath(string $path): string + { + $out = []; + foreach (explode('/', $path) as $segment) { + if ($segment === '..') { + array_pop($out); + } elseif ($segment !== '.' && $segment !== '') { + $out[] = $segment; + } + } + return '/' . implode('/', $out); + } +} diff --git a/src/Optimize/FontHost.php b/src/Optimize/FontHost.php new file mode 100644 index 0000000..c507c16 --- /dev/null +++ b/src/Optimize/FontHost.php @@ -0,0 +1,123 @@ + $cssUrl, 'fonts' => is_array($fonts) ? $fonts : []]; + } + + // localize() runs inside the output buffer of every uncached front-end + // request, so an unreachable endpoint must not be retried each time. + if (is_file($failFile) && (time() - (int) @filemtime($failFile)) < self::RETRY_AFTER) { + return null; + } + + if (! is_dir($dir) && ! wp_mkdir_p($dir)) { + return null; + } + + // A modern UA makes Google serve woff2 @font-face rules. + $response = wp_remote_get($googleUrl, [ + 'timeout' => 10, + 'headers' => [ + 'user-agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0 Safari/537.36', + ], + ]); + if (is_wp_error($response)) { + return $this->fail($failFile); + } + $css = (string) wp_remote_retrieve_body($response); + if ($css === '') { + return $this->fail($failFile); + } + + $fonts = []; + $complete = true; + if (preg_match_all('#https://fonts\.gstatic\.com/[^)\'"]+\.woff2#i', $css, $matches)) { + foreach (array_unique($matches[0]) as $fontUrl) { + $localName = md5($fontUrl) . '.woff2'; + $localPath = $dir . $localName; + $localUrl = WPP_CACHE_URL . 'fonts/' . $localName; + + if (! is_file($localPath)) { + $fontResponse = wp_remote_get($fontUrl, ['timeout' => 10]); + if (is_wp_error($fontResponse)) { + $complete = false; + continue; + } + $body = (string) wp_remote_retrieve_body($fontResponse); + if ($body === '') { + $complete = false; + continue; + } + // Rewriting the CSS after a failed write caches @font-face + // rules pointing at files that do not exist. + if (file_put_contents($localPath, $body, LOCK_EX) === false) { + $complete = false; + continue; + } + } + + $css = str_replace($fontUrl, $localUrl, $css); + $fonts[] = $localUrl; + } + } + + // Caching a partial rewrite is permanent: the short-circuit above would + // keep serving faces straight from fonts.gstatic.com for good. + if (! $complete) { + return $this->fail($failFile); + } + + if (file_put_contents($cssFile, $css, LOCK_EX) === false + || file_put_contents($metaFile, (string) wp_json_encode($fonts), LOCK_EX) === false) { + return $this->fail($failFile); + } + + @unlink($failFile); + + return ['css_url' => $cssUrl, 'fonts' => $fonts]; + } + + /** Records the failure so the next requests fall back without a round trip. */ + private function fail(string $failFile): ?array + { + if (! is_file($failFile)) { + @file_put_contents($failFile, "\n", LOCK_EX); + return null; + } + @touch($failFile); + + return null; + } +} diff --git a/src/Optimize/HtmlMinifier.php b/src/Optimize/HtmlMinifier.php new file mode 100644 index 0000000..0d57cc0 --- /dev/null +++ b/src/Optimize/HtmlMinifier.php @@ -0,0 +1,113 @@ +/';", ['minify_normal' => 1]); + wpp_not_contains("\x02", $nestedTa, 'html: no control characters leak for textarea'); + wpp_contains('', $nestedTa, 'html: textarea inside a script string is restored'); + + // ---- CSS: an apostrophe in a comment must not protect the rules after it ---- + $apostrophe = $css->minify("/* Don't edit */\n.a { color: red; }\n/* It's fine */\n.b { color: blue; }"); + wpp_contains('.a{color:red}', $apostrophe, 'css: rule between two apostrophe comments survives'); + wpp_contains('.b{color:blue}', $apostrophe, 'css: rule after an apostrophe comment survives'); + wpp_not_contains('edit', $apostrophe, 'css: comments are still removed'); + + // A real string still wins over a comment sequence inside it, and vice versa. + $mixed = $css->minify('.a::after{content:"it\'s"}/* gone */.b{color:red}'); + wpp_contains('content:"it\'s"', $mixed, 'css: apostrophe inside a string literal preserved'); + wpp_contains('.b{color:red}', $mixed, 'css: rule after the string survives'); + wpp_not_contains('gone', $mixed, 'css: comment after a string is removed'); + + // ---- HTML remove_quotes: never absorb the slash of a self-closing tag ---- + $link = $html->minify('', ['remove_quotes' => 1]); + wpp_contains('href="https://site.test/a.css"', $link, 'html: value before /> keeps its quotes'); + wpp_contains('rel=stylesheet', $link, 'html: quotes still dropped where it is safe'); + + $img = $html->minify('', ['remove_quotes' => 1]); + wpp_contains('src="/a/b.png"', $img, 'html: img src before /> keeps its quotes'); + + $spaced = $html->minify('', ['remove_quotes' => 1]); + wpp_contains('src=/a/b.png', $spaced, 'html: whitespace-terminated value still unquoted'); + + // ---- HTML remove_quotes: body text is not markup ---- + $prose = $html->minify('

    Add type="text/css" to the tag.

    ', ['remove_quotes' => 1]); + wpp_contains('type="text/css"', $prose, 'html: inline code in body text is untouched'); + + // ---- JS: a regex literal after a keyword ---- + $afterKeyword = $js->minify('function f(s){return /["\']/.test(s)}var b="http://a.com/x";'); + wpp_contains('http://a.com/x', $afterKeyword, 'js: code after a regex containing quotes survives'); + wpp_contains('/["\']/', $afterKeyword, 'js: the regex literal itself is intact'); + + wpp_contains('/a b/', $js->minify('function g(s){return /a b/.test(s)}'), 'js: whitespace inside a regex is not collapsed'); + + // A property named like a keyword is an operand, so '/' is division. + $property = $js->minify('var n = a.case / 2, s = "http://x/y";'); + wpp_contains('"http://x/y"', $property, 'js: division after a keyword-named property'); + + // ---- JS: division after a postfix ++/-- ---- + $postfix = $js->minify('var x = i++ / 2, s = "a/b"; var t = "c"; var u = "http://x/y/z";'); + wpp_contains('"http://x/y/z"', $postfix, 'js: code after i++ / 2 survives'); + wpp_contains('"a/b"', $postfix, 'js: string containing a slash is intact'); + + $postfixDec = $js->minify('var x = i-- / 2, s = "a/b"; var t = "c"; var u = "http://x/y/z";'); + wpp_contains('"http://x/y/z"', $postfixDec, 'js: code after i-- / 2 survives'); + + // ---- HTML: whitespace between inline elements is significant ---- + $inline = $html->minify('

    Hello world

    ', ['minify_aggressive' => 1]); + wpp_contains(' ', $inline, 'html: space between inline elements kept'); + wpp_contains( + ' minify('

    first second

    ', ['minify_aggressive' => 1]), + 'html: space between adjacent links kept' + ); + wpp_contains( + '

    hi

    ', + $html->minify("
    \n

    hi

    \n
    ", ['minify_aggressive' => 1]), + 'html: whitespace around block elements still collapsed' + ); + + // Attribute values decide what a form submits. + wpp_contains('value="a b"', $html->minify('', ['minify_normal' => 1]), 'html: attribute whitespace preserved'); + wpp_contains('

    a b

    ', $html->minify('

    a b

    ', ['minify_normal' => 1]), 'html: text whitespace still collapsed'); + + // ---- CSS url(): quotes are re-emitted, parens inside quotes match ---- + $src = 'https://site.test/wp-content/themes/t/style.css'; + wpp_contains( + 'url("https://site.test/wp-content/themes/t/img/my logo.png")', + $css->process('.a{background:url("img/my logo.png")}', $src), + 'css: a url with a space stays quoted' + ); + wpp_contains( + 'url("https://site.test/wp-content/themes/t/img/logo(2).png")', + $css->process('.a{background:url("img/logo(2).png")}', $src), + 'css: a quoted url with parens is absolutized' + ); + wpp_contains( + "url('https://site.test/wp-content/themes/t/img/a.png')", + $css->process(".a{background:url('img/a.png')}", $src), + 'css: single quotes are preserved' + ); + + // ---- UsedCss ---- + $abs = rtrim(ABSPATH, '/') . '/'; + @mkdir($abs . 'wp-content/themes/u', 0777, true); + $used = new UsedCss(); + + file_put_contents($abs . 'wp-content/themes/u/braces.css', '.icon::after{content:"}"}.btn{color:red}.card{color:blue}'); + $braces = $used->build('', ['/wp-content/themes/u/braces.css'], []); + wpp_contains('content:"}"}', $braces, 'usedcss: the rule holding a brace in a string is closed'); + wpp_not_contains('content:"}.btn', $braces, 'usedcss: the brace in a string does not swallow the next rule'); + wpp_contains('.btn{color:red}', $braces, 'usedcss: rule after a brace in a string survives'); + wpp_contains('.card{color:blue}', $braces, 'usedcss: last rule survives a brace in a string'); + + file_put_contents($abs . 'wp-content/themes/u/attrs.css', 'a[href="#top"]{color:red}.x:not(.js-hidden){color:blue}'); + $attrs = $used->build('t', ['/wp-content/themes/u/attrs.css'], []); + wpp_contains('a[href="#top"]', $attrs, 'usedcss: attribute-selector value is not read as an id token'); + wpp_contains('.x:not(.js-hidden)', $attrs, 'usedcss: :not() argument is not read as a class token'); + + file_put_contents($abs . 'wp-content/themes/u/unused.css', '.present{color:red}.absent{color:blue}'); + $unused = $used->build('', ['/wp-content/themes/u/unused.css'], []); + wpp_contains('.present', $unused, 'usedcss: a used rule is kept'); + wpp_not_contains('.absent', $unused, 'usedcss: an unused rule is still dropped'); + + // ---- FontHost ---- + $fontHost = new FontHost(); + wpp_same(null, $fontHost->localize('https://evil.test/css?family=X'), 'fonthost: a non-google host is refused'); + wpp_same([], WPP_Test_State::$httpCalls, 'fonthost: a refused url is never fetched'); + + $googleUrl = 'https://fonts.googleapis.com/css?family=Test'; + $fontUrl = 'https://fonts.gstatic.com/s/test/v1/abc.woff2'; + WPP_Test_State::$httpResponses[$googleUrl] = ['body' => '@font-face{src:url(' . $fontUrl . ') format("woff2")}']; + WPP_Test_State::$httpResponses[$fontUrl] = ['body' => 'woff2-bytes']; + + // Occupying the target path with a directory makes the font write fail. + @mkdir(WPP_CACHE_DIR . 'fonts/', 0777, true); + @mkdir(WPP_CACHE_DIR . 'fonts/' . md5($fontUrl) . '.woff2', 0777, true); + + set_error_handler(static fn (): bool => true); + $hosted = $fontHost->localize($googleUrl); + restore_error_handler(); + + // Hosting a stylesheet whose faces are still remote is worse than not + // hosting it: the short-circuit makes it permanent, and the admin reports + // the fonts as local while every visitor still hits fonts.gstatic.com. + wpp_same(null, $hosted, 'fonthost: a partly localised stylesheet is not hosted'); + wpp_ok( + ! is_file(WPP_CACHE_DIR . 'fonts/' . md5($googleUrl) . '.css'), + 'fonthost: nothing is cached when a font write fails, so the next request retries' + ); +}; diff --git a/tests/suites/minifiers.php b/tests/suites/minifiers.php new file mode 100644 index 0000000..e902281 --- /dev/null +++ b/tests/suites/minifiers.php @@ -0,0 +1,122 @@ +minify('var re = /a\/b[/]/g; var x = 1/2;'), 'js: regex literal with escaped slash'); + wpp_contains('/x/g', $js->minify('var a=b/c; var d=/x/g.test(s);'), 'js: regex vs division'); + wpp_contains('/z/', $js->minify('var x = (a+b)/2; var r=/z/;'), 'js: division after paren then regex'); + wpp_contains('${', $js->minify('var s = `a ${ b } c`;'), 'js: template literal interpolation kept'); + wpp_contains('http://x.com/*not a comment*/', $js->minify('var s = "http://x.com/*not a comment*/";'), 'js: block-comment sequence inside string'); + wpp_contains('a // b', $js->minify('var s = "a // b"; var y=1;'), 'js: line-comment sequence inside string'); + wpp_contains("'", $js->minify("var s = 'it\\'s';"), 'js: escaped quote inside string'); + + // Real comments are removed. + wpp_not_contains('kill me', $js->minify("var a=1; // kill me\nvar b=2;"), 'js: line comment removed'); + wpp_not_contains('kill me', $js->minify("var a=1; /* kill me */ var b=2;"), 'js: block comment removed'); + + // ASI safety: statements separated only by newlines must not be joined. + $asi = $js->minify("var a = 1\nvar b = 2\nconsole.log(a+b)"); + wpp_same(2, substr_count($asi, 'var'), 'js: both statements survive ASI'); + wpp_ok( + str_contains($asi, "\n") || str_contains($asi, ';'), + 'js: statements stay separated (newline or semicolon)' + ); + + // Minification actually shrinks typical code. + $long = "function add ( a , b ) {\n // sum\n return a + b ;\n}\n"; + wpp_ok(strlen($js->minify($long)) < strlen($long), 'js: output is smaller'); + + // ---- CSS ---- + wpp_contains('base64,PHN2Zz48L3N2Zz4=', $css->minify('.a{background:url(data:image/svg+xml;base64,PHN2Zz48L3N2Zz4=)}'), 'css: base64 data uri intact'); + wpp_contains('a(1).png', $css->minify('.a{background:url("a(1).png")}'), 'css: parens inside quoted url'); + wpp_contains('--x', $css->minify(':root{--x: 10px;--y:calc(var(--x) * 2)}'), 'css: custom properties kept'); + wpp_contains('@media', $css->minify('@media (min-width: 700px){.a{color:red}}'), 'css: media query kept'); + wpp_contains('700px', $css->minify('@media (min-width: 700px){.a{color:red}}'), 'css: media query value kept'); + wpp_contains('a;b}c', $css->minify('.a::after{content:"a;b}c"}'), 'css: braces and semicolons inside string'); + wpp_contains('/* x */', $css->minify('.a::after{content:"/* x */"}'), 'css: comment sequence inside string'); + wpp_contains('!important', $css->minify('.a{color:red !important}'), 'css: important kept'); + wpp_contains('http://x', $css->minify('a[href^="http://x"]{color:red}'), 'css: double slash in attribute selector'); + wpp_not_contains('kill me', $css->minify('/* kill me */ .a{color:red}'), 'css: real comment removed'); + wpp_ok(strlen($css->minify(".a {\n color : red ;\n}\n")) < 20, 'css: whitespace collapsed'); + + // ---- CSS url() rewriting when a stylesheet moves into the cache dir ---- + // Regression: a '#' delimiter in the "already absolute" guard ended the + // pattern at the fragment alternative, so the guard matched nothing and + // every url() was rewritten, including base64 fonts. That broke Dashicons. + $src = 'http://localhost:10092/wp-includes/css/dashicons.min.css'; + + $dataUri = $css->process('.a{background:url(data:image/png;base64,AAAA)}', $src); + wpp_contains('url(data:image/png;base64,AAAA)', $dataUri, 'css: data uri left untouched'); + wpp_not_contains('/data:', $dataUri, 'css: data uri is never prefixed with a base path'); + + wpp_contains( + 'url(https://cdn.example.com/x.png)', + $css->process('.a{background:url(https://cdn.example.com/x.png)}', $src), + 'css: absolute url left untouched' + ); + wpp_contains( + 'url(//cdn.example.com/x.png)', + $css->process('.a{background:url(//cdn.example.com/x.png)}', $src), + 'css: protocol-relative url left untouched' + ); + wpp_contains( + 'url(#grad)', + $css->process('.a{fill:url(#grad)}', $src), + 'css: svg fragment reference left untouched' + ); + wpp_contains( + 'url(about:blank)', + $css->process('.a{background:url(about:blank)}', $src), + 'css: non-http scheme left untouched' + ); + + // Relative urls resolve against the stylesheet, keeping a non-default port. + wpp_contains( + 'url(http://localhost:10092/wp-includes/img/x.png)', + $css->process('.a{background:url(../img/x.png)}', $src), + 'css: relative url resolves and keeps the port' + ); + wpp_contains( + 'url(http://localhost:10092/img/x.png)', + $css->process('.a{background:url(/img/x.png)}', $src), + 'css: root-relative url keeps the port' + ); + wpp_contains( + 'url(https://example.test/wp-includes/img/x.png)', + $css->process('.a{background:url(../img/x.png)}', 'https://example.test/wp-includes/css/a.css'), + 'css: default port is not appended' + ); + + // @import is resolved the same way. + wpp_contains( + '@import "http://localhost:10092/wp-includes/css/other.css"', + $css->process('@import "other.css";', $src), + 'css: relative @import resolved' + ); + + // ---- HTML ---- + $opts = ['minify_normal' => true, 'remove_comments' => true]; + $out = $html->minify("

    hi

    \n\n", $opts); + wpp_not_contains('gone', $out, 'html: comment removed'); + wpp_contains('

    hi

    ', $out, 'html: markup preserved'); + + // Conditional comments must survive comment removal. + $cond = $html->minify('
    x
    ', $opts); + wpp_contains('[if IE]', $cond, 'html: conditional comment preserved'); + + // Content of pre/textarea/script must not be whitespace-collapsed. + $pre = $html->minify("
    a   b\n  c
    ", $opts); + wpp_contains("a b", $pre, 'html: pre content whitespace preserved'); + $ta = $html->minify("", $opts); + wpp_contains('a b', $ta, 'html: textarea content preserved'); +}; diff --git a/tests/suites/parser-fixes.php b/tests/suites/parser-fixes.php new file mode 100644 index 0000000..6c8cfaf --- /dev/null +++ b/tests/suites/parser-fixes.php @@ -0,0 +1,209 @@ + "{$body}"; + + $reset = static function (): void { + foreach (['wpp_css', 'wpp_js', 'wpp_media', 'wpp_cdn', 'wpp_html'] as $option) { + update_option($option, []); + } + }; + + $abs = rtrim(ABSPATH, '/') . '/'; + @mkdir($abs . 'wp-content/themes/fx', 0777, true); + @mkdir($abs . 'wp-content/uploads', 0777, true); + + // ---- Google Fonts: css2 endpoint and every family survive combining ---- + $reset(); + $settings->update('css', ['combine_fonts' => true]); + + $out = $parser()->parse($page( + '' + )); + wpp_contains('fonts.googleapis.com/css2?family=', $out, 'css2 endpoint is preserved'); + wpp_contains('family=Inter:wght@400;700', $out, 'first css2 family is kept'); + wpp_contains('family=Lora:wght@400', $out, 'second css2 family is kept'); + + // A v1 link still rebuilds against v1 syntax. + $reset(); + $settings->update('css', ['combine_fonts' => true]); + $out = $parser()->parse($page( + '' + )); + wpp_contains('/css?family=Open+Sans|Roboto', $out, 'v1 families keep the pipe-joined syntax'); + + // ---- media attribute survives combining and used-CSS ---- + $reset(); + file_put_contents($abs . 'screen.css', '.screen{color:red}'); + file_put_contents($abs . 'print.css', '.print{color:black}'); + $settings->update('css', ['combine' => ['/screen.css' => true, '/print.css' => true]]); + + $out = $parser()->parse($page( + '' + )); + wpp_contains('media="print"', $out, 'print sheets are bundled separately and keep media'); + wpp_same(2, substr_count($out, '/wpp-cache/'), 'one bundle per media value'); + + $reset(); + $settings->update('css', ['remove_unused' => true]); + $out = $parser()->parse($page('')); + wpp_contains('href="/wp-content/themes/fx/print.css" media="print"', $out, 'media-scoped sheet is not swept into used-CSS'); + + // ---- combined JS lands where the first combined tag stood ---- + $reset(); + file_put_contents($abs . 'jquery.js', 'var jq=1;'); + $settings->update('js', ['combine' => ['/jquery.js' => true]]); + + $out = $parser()->parse($page('')); + $bundle = strpos($out, '/wpp-cache/'); + $inline = strpos($out, 'jQuery(1);'); + wpp_ok($bundle !== false, 'js bundle was emitted'); + wpp_ok($bundle !== false && $inline !== false && $bundle < $inline, 'bundle runs before the inline code that depends on it'); + + // ---- used-CSS cache is keyed by the safelist ---- + $reset(); + file_put_contents($abs . 'wp-content/themes/fx/used.css', '.always{color:red}.menu-open{display:block}'); + $usedPage = '
    '; + + $settings->update('css', ['remove_unused' => true, 'used_safelist' => []]); + $out = $parser()->parse($usedPage); + wpp_contains('wpp-used-css', $out, 'used-CSS is inlined'); + wpp_not_contains('menu-open', $out, 'a class absent from the HTML is stripped'); + + $settings->update('css', ['used_safelist' => ['.menu-open']]); + $out = $parser()->parse($usedPage); + wpp_contains('menu-open', $out, 'safelist change invalidates the cached used-CSS'); + + // ---- videos_exclude_urls is honored ---- + $reset(); + $settings->update('media', ['videos_lazy' => true, 'videos_exclude_urls' => ['https://www.youtube.com/embed/LIVE']]); + + $out = $parser()->parse($page('')); + wpp_not_contains('loading="lazy"', $out, 'excluded video iframe is not lazy-loaded'); + + $out = $parser()->parse($page('')); + wpp_contains('loading="lazy"', $out, 'other iframes are still lazy-loaded'); + + // ---- next-gen sources are probed against the origin URL, not the CDN one ---- + $reset(); + file_put_contents($abs . 'wp-content/uploads/logo.png', 'png'); + file_put_contents($abs . 'wp-content/uploads/logo.png.webp', 'webp'); + $settings->update('media', ['webp' => true]); + + $out = $parser()->parse($page('')); + wpp_contains('type="image/webp"', $out, 'webp source is emitted for a srcset-less image'); + + $settings->update('cdn', ['enabled' => true, 'hostname' => 'https://cdn.example.com']); + $out = $parser()->parse($page('')); + wpp_contains('type="image/webp"', $out, 'webp source survives the CDN rewrite'); + wpp_contains('cdn.example.com/wp-content/uploads/logo.png.webp', $out, 'webp source is served from the CDN'); + + // ---- cdn.exclude understands the wildcard tokens the UI documents ---- + $reset(); + $settings->update('cdn', [ + 'enabled' => true, + 'hostname' => 'https://cdn.example.com', + 'exclude' => ['https://example.test/wp-content/uploads/{numbers}/{numbers}/{any}'], + ]); + + $out = $parser()->parse($page('')); + wpp_contains('example.test/wp-content/uploads/2026/01/photo.jpg', $out, 'wildcard exclusion keeps the origin URL'); + wpp_not_contains('cdn.example.com', $out, 'excluded image never reaches the CDN'); + + // ---- LCP preload resolves to the same candidate as the ---- + $reset(); + $settings->update('media', ['lcp_images' => 1]); + + $out = $parser()->parse($page( + '' + )); + wpp_contains('imagesrcset="/hero-768.jpg 768w, /hero.jpg 2000w"', $out, 'preload carries the srcset'); + wpp_contains('imagesizes="(max-width: 768px) 100vw, 1024px"', $out, 'preload carries the sizes'); + + // ---- stylesheets are re-inserted in place, not at the end of ---- + $reset(); + file_put_contents($abs . 'theme.css', '.theme{color:green}'); + $settings->update('css', ['combine' => ['/theme.css' => true]]); + + $out = $parser()->parse(''); + $bundle = strpos($out, '/wpp-cache/'); + $custom = strpos($out, 'id="custom"'); + wpp_ok($bundle !== false, 'css bundle was emitted'); + wpp_ok($bundle !== false && $custom !== false && $bundle < $custom, 'bundle stays ahead of the inline style that overrides it'); + + // ---- deferring moves media onto the onload handler ---- + $reset(); + $settings->update('css', ['defer' => true]); + + $out = $parser()->parse($page('')); + preg_match('#]*rel="preload"[^>]*>#', $out, $m); + wpp_not_contains('media="print"', $m[0] ?? '', 'preload link carries no media attribute'); + wpp_contains('